update typescript errors for vercel

This commit is contained in:
Jeff Emmett 2025-11-10 11:19:24 -08:00
parent f8e4647e1a
commit 4815fa4a23
29 changed files with 149 additions and 219 deletions

View File

@ -130,5 +130,6 @@ The Fathom transcript shape includes:

View File

@ -81,5 +81,6 @@ You can also manually edit the environment by:

View File

@ -97,23 +97,29 @@ export function applyAutomergePatchesToTLStore(
}
}
const record = updatedObjects[id] || (existingRecord ? JSON.parse(JSON.stringify(existingRecord)) : defaultRecord)
let record = updatedObjects[id] || (existingRecord ? JSON.parse(JSON.stringify(existingRecord)) : defaultRecord)
// CRITICAL: Ensure typeName matches ID pattern (fixes misclassification)
// Note: obsidian_vault records are skipped above, so we don't need to handle them here
if (typeof id === 'string') {
let correctTypeName = record.typeName
if (id.startsWith('shape:') && record.typeName !== 'shape') {
record.typeName = 'shape'
correctTypeName = 'shape'
} else if (id.startsWith('page:') && record.typeName !== 'page') {
record.typeName = 'page'
correctTypeName = 'page'
} else if (id.startsWith('camera:') && record.typeName !== 'camera') {
record.typeName = 'camera'
correctTypeName = 'camera'
} else if (id.startsWith('instance:') && record.typeName !== 'instance') {
record.typeName = 'instance'
correctTypeName = 'instance'
} else if (id.startsWith('pointer:') && record.typeName !== 'pointer') {
record.typeName = 'pointer'
correctTypeName = 'pointer'
} else if (id.startsWith('document:') && record.typeName !== 'document') {
record.typeName = 'document'
correctTypeName = 'document'
}
// Create new object with correct typeName if it changed
if (correctTypeName !== record.typeName) {
record = { ...record, typeName: correctTypeName }
}
}

View File

@ -219,19 +219,19 @@ export class CloudflareNetworkAdapter extends NetworkAdapter {
// We need to handle both binary and text messages
if (event.data instanceof ArrayBuffer) {
console.log('🔌 CloudflareAdapter: Received binary message (Automerge protocol)')
// Handle binary Automerge sync messages - pass directly to Repo
// Automerge Repo expects binary sync messages as ArrayBuffer
// Handle binary Automerge sync messages - convert ArrayBuffer to Uint8Array
// Automerge Repo expects binary sync messages as Uint8Array
this.emit('message', {
type: 'sync',
data: event.data
data: new Uint8Array(event.data)
})
} else if (event.data instanceof Blob) {
// Handle Blob messages (convert to ArrayBuffer)
// Handle Blob messages (convert to Uint8Array)
event.data.arrayBuffer().then((buffer) => {
console.log('🔌 CloudflareAdapter: Received Blob message, converted to ArrayBuffer')
console.log('🔌 CloudflareAdapter: Received Blob message, converted to Uint8Array')
this.emit('message', {
type: 'sync',
data: buffer
data: new Uint8Array(buffer)
})
})
} else {

View File

@ -1488,7 +1488,7 @@ export function useAutomergeStoreV2({
for (const record of failedRecords) {
try {
// Additional cleanup for failed records - create deep copy
const fixedRecord = JSON.parse(JSON.stringify(record))
let fixedRecord = JSON.parse(JSON.stringify(record))
// Fix instance records specifically
if (fixedRecord.typeName === 'instance') {

View File

@ -143,13 +143,13 @@ export function useAutomergeSync(config: AutomergeSyncConfig): TLStoreWithStatus
return {
status: isLoading ? 'loading' : 'not-synced',
connectionStatus: 'offline',
store: null
store: undefined
}
}
return {
status: 'synced',
connectionStatus: 'online',
status: 'synced-remote' as const,
connectionStatus: 'online' as const,
store
}
}, [store, isLoading])
@ -164,5 +164,5 @@ export function useAutomergeSync(config: AutomergeSyncConfig): TLStoreWithStatus
return {
...storeWithStatus,
presence
}
} as TLStoreWithStatus & { presence: typeof presence }
}

View File

@ -197,7 +197,7 @@ export const StandardizedToolWrapper: React.FC<StandardizedToolWrapperProps> = (
onPointerDown={handleHeaderPointerDown}
onMouseEnter={() => setIsHoveringHeader(true)}
onMouseLeave={() => setIsHoveringHeader(false)}
onMouseDown={(e) => {
onMouseDown={(_e) => {
// Ensure selection happens on mouse down for immediate visual feedback
if (editor && shapeId && !isSelected) {
editor.setSelectedShapes([shapeId])

View File

@ -258,5 +258,6 @@ export const LocationDashboard: React.FC = () => {

View File

@ -229,5 +229,6 @@ export const LocationMap: React.FC<LocationMapProps> = ({

View File

@ -8,7 +8,7 @@ import {
import React from "react"
import { ShareLocation } from "./ShareLocation"
export function LocationShareDialog({ onClose }: TLUiDialogProps) {
export function LocationShareDialog({ onClose: _onClose }: TLUiDialogProps) {
return (
<>
<TldrawUiDialogHeader>

View File

@ -171,5 +171,6 @@ export const LocationViewer: React.FC<LocationViewerProps> = ({ shareToken }) =>

View File

@ -138,5 +138,6 @@ export const ShareSettingsComponent: React.FC<ShareSettingsProps> = ({ onSetting

View File

@ -413,5 +413,6 @@

View File

@ -30,21 +30,21 @@ declare global {
}
interface SpeechRecognitionResultList {
length: number
readonly length: number
item(index: number): SpeechRecognitionResult
[index: number]: SpeechRecognitionResult
}
interface SpeechRecognitionResult {
length: number
readonly length: number
item(index: number): SpeechRecognitionAlternative
[index: number]: SpeechRecognitionAlternative
isFinal: boolean
readonly isFinal: boolean
}
interface SpeechRecognitionAlternative {
transcript: string
confidence: number
readonly transcript: string
readonly confidence: number
}
var SpeechRecognition: {

View File

@ -155,7 +155,7 @@ export class HoloSphereService {
let unsubscribe: (() => void) | undefined = undefined
if (this.sphere.subscribe) {
try {
unsubscribe = this.sphere.subscribe(holon, lens, (data: any, key?: string) => {
const subscribeResult = this.sphere.subscribe(holon, lens, (data: any, key?: string) => {
subscriptionActive = true
console.log(`📥 Subscription callback fired for ${lens}:`, { data, key, dataType: typeof data, isObject: typeof data === 'object', isArray: Array.isArray(data) })
@ -183,7 +183,18 @@ export class HoloSphereService {
console.log(`📥 Current collected data for ${lens}:`, Object.keys(collectedData).length, 'keys')
}
})
// Handle Promise if subscribe returns one
if (subscribeResult instanceof Promise) {
subscribeResult.then((result) => {
unsubscribe = result?.unsubscribe || undefined
console.log(`✅ Subscribe called successfully for ${lens}`)
}).catch((err) => {
console.error(`❌ Error in subscribe promise for ${lens}:`, err)
})
} else {
unsubscribe = subscribeResult?.unsubscribe || undefined
console.log(`✅ Subscribe called successfully for ${lens}`)
}
} catch (subError) {
console.error(`❌ Error calling subscribe for ${lens}:`, subError)
}

View File

@ -66,9 +66,10 @@ export class LocationStorageService {
private async ensureDirectory(path: string[]): Promise<void> {
try {
const dirPath = odd.path.directory(...path);
const exists = await this.fs.exists(dirPath as any);
const fs = this.fs as any;
const exists = await fs.exists(dirPath);
if (!exists) {
await this.fs.mkdir(dirPath as any);
await fs.mkdir(dirPath);
}
} catch (error) {
console.error('Error ensuring directory:', error);
@ -81,10 +82,11 @@ export class LocationStorageService {
*/
async saveLocation(location: LocationData): Promise<void> {
try {
const filePath = odd.path.file(...this.locationsPath, `${location.id}.json`);
const filePath = (odd.path as any).file(...this.locationsPath, `${location.id}.json`);
const content = new TextEncoder().encode(JSON.stringify(location, null, 2));
await this.fs.write(filePath as any, content as any);
await this.fs.publish();
const fs = this.fs as any;
await fs.write(filePath, content);
await fs.publish();
} catch (error) {
console.error('Error saving location:', error);
throw error;
@ -96,12 +98,13 @@ export class LocationStorageService {
*/
async getLocation(locationId: string): Promise<LocationData | null> {
try {
const filePath = odd.path.file(...this.locationsPath, `${locationId}.json`);
const exists = await this.fs.exists(filePath as any);
const filePath = (odd.path as any).file(...this.locationsPath, `${locationId}.json`);
const fs = this.fs as any;
const exists = await fs.exists(filePath);
if (!exists) {
return null;
}
const content = await this.fs.read(filePath as any);
const content = await fs.read(filePath);
const text = new TextDecoder().decode(content as Uint8Array);
return JSON.parse(text) as LocationData;
} catch (error) {
@ -116,12 +119,13 @@ export class LocationStorageService {
async createShare(share: LocationShare): Promise<void> {
try {
// Save share metadata in private directory
const sharePath = odd.path.file(...this.sharesPath, `${share.id}.json`);
const sharePath = (odd.path as any).file(...this.sharesPath, `${share.id}.json`);
const shareContent = new TextEncoder().encode(JSON.stringify(share, null, 2));
await this.fs.write(sharePath as any, shareContent as any);
const fs = this.fs as any;
await fs.write(sharePath, shareContent);
// Create public reference file for share validation (only token, not full data)
const publicSharePath = odd.path.file(...this.publicSharesPath, `${share.shareToken}.json`);
const publicSharePath = (odd.path as any).file(...this.publicSharesPath, `${share.shareToken}.json`);
const publicShareRef = {
shareToken: share.shareToken,
shareId: share.id,
@ -129,9 +133,9 @@ export class LocationStorageService {
expiresAt: share.expiresAt,
};
const publicContent = new TextEncoder().encode(JSON.stringify(publicShareRef, null, 2));
await this.fs.write(publicSharePath as any, publicContent as any);
await fs.write(publicSharePath, publicContent);
await this.fs.publish();
await fs.publish();
} catch (error) {
console.error('Error creating share:', error);
throw error;
@ -144,24 +148,25 @@ export class LocationStorageService {
async getShareByToken(shareToken: string): Promise<LocationShare | null> {
try {
// First check public reference
const publicSharePath = odd.path.file(...this.publicSharesPath, `${shareToken}.json`);
const publicExists = await this.fs.exists(publicSharePath as any);
const publicSharePath = (odd.path as any).file(...this.publicSharesPath, `${shareToken}.json`);
const fs = this.fs as any;
const publicExists = await fs.exists(publicSharePath);
if (!publicExists) {
return null;
}
const publicContent = await this.fs.read(publicSharePath as any);
const publicContent = await fs.read(publicSharePath);
const publicText = new TextDecoder().decode(publicContent as Uint8Array);
const publicRef = JSON.parse(publicText);
// Now get full share from private directory
const sharePath = odd.path.file(...this.sharesPath, `${publicRef.shareId}.json`);
const shareExists = await this.fs.exists(sharePath as any);
const sharePath = (odd.path as any).file(...this.sharesPath, `${publicRef.shareId}.json`);
const shareExists = await fs.exists(sharePath);
if (!shareExists) {
return null;
}
const shareContent = await this.fs.read(sharePath as any);
const shareContent = await fs.read(sharePath);
const shareText = new TextDecoder().decode(shareContent as Uint8Array);
return JSON.parse(shareText) as LocationShare;
} catch (error) {
@ -176,12 +181,13 @@ export class LocationStorageService {
async getAllShares(): Promise<LocationShare[]> {
try {
const dirPath = odd.path.directory(...this.sharesPath);
const exists = await this.fs.exists(dirPath as any);
const fs = this.fs as any;
const exists = await fs.exists(dirPath);
if (!exists) {
return [];
}
const files = await this.fs.ls(dirPath as any);
const files = await fs.ls(dirPath);
const shares: LocationShare[] = [];
for (const fileName of Object.keys(files)) {
@ -206,12 +212,13 @@ export class LocationStorageService {
*/
private async getShareById(shareId: string): Promise<LocationShare | null> {
try {
const sharePath = odd.path.file(...this.sharesPath, `${shareId}.json`);
const exists = await this.fs.exists(sharePath as any);
const sharePath = (odd.path as any).file(...this.sharesPath, `${shareId}.json`);
const fs = this.fs as any;
const exists = await fs.exists(sharePath);
if (!exists) {
return null;
}
const content = await this.fs.read(sharePath as any);
const content = await fs.read(sharePath);
const text = new TextDecoder().decode(content as Uint8Array);
return JSON.parse(text) as LocationShare;
} catch (error) {

View File

@ -43,5 +43,6 @@ export interface GeolocationPosition {

View File

@ -206,7 +206,7 @@ export function Board() {
const store = {
store: storeWithHandle.store,
status: storeWithHandle.status,
connectionStatus: storeWithHandle.connectionStatus,
...('connectionStatus' in storeWithHandle ? { connectionStatus: storeWithHandle.connectionStatus } : {}),
error: storeWithHandle.error
}
const automergeHandle = storeWithHandle.handle
@ -405,11 +405,11 @@ export function Board() {
const isInputFocused = (target && (
target.tagName === 'INPUT' ||
target.tagName === 'TEXTAREA' ||
target.isContentEditable
(target instanceof HTMLElement && target.isContentEditable)
)) || (activeElement && (
activeElement.tagName === 'INPUT' ||
activeElement.tagName === 'TEXTAREA' ||
activeElement.isContentEditable
(activeElement instanceof HTMLElement && activeElement.isContentEditable)
));
// If an input is focused, let it handle Escape (don't prevent default)

View File

@ -25,5 +25,6 @@ export const LocationDashboardRoute: React.FC = () => {

View File

@ -25,5 +25,6 @@ export const LocationShareCreate: React.FC = () => {

View File

@ -39,5 +39,6 @@ export const LocationShareView: React.FC = () => {

View File

@ -79,8 +79,8 @@ interface Message {
// Update the ChatBox component to accept userName
export const ChatBox: React.FC<IChatBoxShape["props"]> = ({
roomId,
w,
h,
w: _w,
h: _h,
userName,
}) => {
const [messages, setMessages] = useState<Message[]>([])

View File

@ -113,6 +113,15 @@ export class FathomTranscriptShape extends BaseBoxShapeUtil<IFathomTranscript> {
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`
}
const buttonStyle: React.CSSProperties = {
padding: '4px 8px',
fontSize: '10px',
border: '1px solid #ccc',
borderRadius: '4px',
backgroundColor: 'white',
cursor: 'pointer',
}
// Custom header content with meeting info and toggle buttons
const headerContent = (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', gap: '8px' }}>

View File

@ -981,7 +981,7 @@ export class ObsNoteShape extends BaseBoxShapeUtil<IObsNoteShape> {
/**
* Sanitize props to ensure all values are JSON serializable
*/
private static sanitizeProps(props: Partial<IObsNoteShape['props']>): IObsNoteShape['props'] {
public static sanitizeProps(props: Partial<IObsNoteShape['props']>): IObsNoteShape['props'] {
// Ensure tags is a proper string array
const tags = Array.isArray(props.tags)
? props.tags.filter(tag => typeof tag === 'string').map(tag => String(tag))

View File

@ -125,6 +125,10 @@ export class HolonIdle extends StateNode {
override onExit = () => {
this.cleanupTooltip()
// Clean up event listeners
if ((this as any).cleanup) {
;(this as any).cleanup()
}
}
private cleanupTooltip = () => {
@ -278,123 +282,6 @@ export class HolonIdle extends StateNode {
}
}
private createHolonShape(clickX?: number, clickY?: number) {
try {
// Store current camera position to prevent it from changing
const currentCamera = this.editor.getCamera()
this.editor.stopCameraAnimation()
// Standardized size: 700x400 (matches default props to fit ID and button)
const shapeWidth = 700
const shapeHeight = 400
// Use click position if available, otherwise fall back to viewport center
let baseX: number
let baseY: number
if (clickX !== undefined && clickY !== undefined) {
// Position new Holon shape at click location (centered on click)
baseX = clickX - shapeWidth / 2 // Center the shape on click
baseY = clickY - shapeHeight / 2 // Center the shape on click
console.log('📍 HolonTool: Calculated base position from click:', { clickX, clickY, baseX, baseY, shapeWidth, shapeHeight })
} else {
// Fallback to viewport center if no click coordinates
const viewport = this.editor.getViewportPageBounds()
const centerX = viewport.x + viewport.w / 2
const centerY = viewport.y + viewport.h / 2
baseX = centerX - shapeWidth / 2 // Center the shape
baseY = centerY - shapeHeight / 2 // Center the shape
}
// Find existing Holon shapes for naming
const allShapes = this.editor.getCurrentPageShapes()
const existingHolonShapes = allShapes.filter(s => s.type === 'Holon')
// ALWAYS use click position directly when provided - user clicked where they want it
// Skip collision detection entirely for user clicks to ensure it appears exactly where clicked
let finalX = baseX
let finalY = baseY
if (clickX !== undefined && clickY !== undefined) {
// User clicked - ALWAYS use that exact position, no collision detection
// This ensures the shape appears exactly where the user clicked
finalX = baseX
finalY = baseY
console.log('📍 Using click position directly (no collision check):', {
clickPosition: { x: clickX, y: clickY },
shapePosition: { x: finalX, y: finalY },
shapeSize: { w: shapeWidth, h: shapeHeight }
})
} else {
// For fallback (no click), use collision detection
const position = findNonOverlappingPosition(
this.editor,
baseX,
baseY,
shapeWidth,
shapeHeight
)
finalX = position.x
finalY = position.y
console.log('📍 No click position - using collision detection:', { finalX, finalY })
}
// Default coordinates (can be changed by user)
const defaultLat = 40.7128 // NYC
const defaultLng = -74.0060
const defaultResolution = 7 // City level
console.log('📍 HolonTool: Final position for shape:', { finalX, finalY, wasOverlap: clickX !== undefined && clickY !== undefined && (finalX !== baseX || finalY !== baseY) })
const holonShape = this.editor.createShape({
type: 'Holon',
x: finalX,
y: finalY,
props: {
w: shapeWidth,
h: shapeHeight,
name: `Holon ${existingHolonShapes.length + 1}`,
description: '',
latitude: defaultLat,
longitude: defaultLng,
resolution: defaultResolution,
holonId: '',
isConnected: false,
isEditing: true,
selectedLens: 'general',
data: {},
connections: [],
lastUpdated: Date.now()
}
})
console.log('✅ Created Holon shape:', holonShape.id)
// Restore camera position if it changed
const newCamera = this.editor.getCamera()
if (currentCamera.x !== newCamera.x || currentCamera.y !== newCamera.y || currentCamera.z !== newCamera.z) {
this.editor.setCamera(currentCamera, { animation: { duration: 0 } })
}
// Select the new shape
setTimeout(() => {
// Preserve camera position when selecting
const cameraBeforeSelect = this.editor.getCamera()
this.editor.stopCameraAnimation()
this.editor.setSelectedShapes([`shape:${holonShape.id}`] as any)
this.editor.setCurrentTool('select')
// Restore camera if it changed during selection
const cameraAfterSelect = this.editor.getCamera()
if (cameraBeforeSelect.x !== cameraAfterSelect.x || cameraBeforeSelect.y !== cameraAfterSelect.y || cameraBeforeSelect.z !== cameraAfterSelect.z) {
this.editor.setCamera(cameraBeforeSelect, { animation: { duration: 0 } })
}
}, 100)
} catch (error) {
console.error('❌ Error creating Holon shape:', error)
}
}
private addRefreshAllListener() {
// Listen for refresh-all-holons event
const handleRefreshAll = async () => {
@ -439,11 +326,4 @@ export class HolonIdle extends StateNode {
// Store cleanup function for later use
;(this as any).cleanup = cleanup
}
onExit() {
// Clean up event listeners
if ((this as any).cleanup) {
;(this as any).cleanup()
}
}
}

View File

@ -21,6 +21,38 @@ export class ObsNoteTool extends StateNode {
this.addRefreshAllListener()
}
}
private addRefreshAllListener() {
// Listen for refresh-all-obsnotes event
const handleRefreshAll = async () => {
const shapeUtil = new ObsNoteShape(this.editor)
shapeUtil.editor = this.editor
const result = await shapeUtil.refreshAllFromVault()
if (result.success > 0) {
alert(`✅ Refreshed ${result.success} notes from vault!${result.failed > 0 ? ` (${result.failed} failed)` : ''}`)
} else {
alert('❌ Failed to refresh any notes. Check console for details.')
}
}
window.addEventListener('refresh-all-obsnotes', handleRefreshAll)
// Clean up listener when tool is deselected
const cleanup = () => {
window.removeEventListener('refresh-all-obsnotes', handleRefreshAll)
}
// Store cleanup function for later use
;(this as any).cleanup = cleanup
}
onExit() {
// Clean up event listeners
if ((this as any).cleanup) {
;(this as any).cleanup()
}
}
}
export class ObsNoteIdle extends StateNode {
@ -101,6 +133,10 @@ export class ObsNoteIdle extends StateNode {
override onExit = () => {
this.cleanupTooltip()
// Clean up event listeners
if ((this as any).cleanup) {
;(this as any).cleanup()
}
}
private cleanupTooltip = () => {
@ -182,36 +218,4 @@ export class ObsNoteIdle extends StateNode {
console.error('❌ Error creating ObsidianBrowser shape:', error)
}
}
private addRefreshAllListener() {
// Listen for refresh-all-obsnotes event
const handleRefreshAll = async () => {
const shapeUtil = new ObsNoteShape(this.editor)
shapeUtil.editor = this.editor
const result = await shapeUtil.refreshAllFromVault()
if (result.success > 0) {
alert(`✅ Refreshed ${result.success} notes from vault!${result.failed > 0 ? ` (${result.failed} failed)` : ''}`)
} else {
alert('❌ Failed to refresh any notes. Check console for details.')
}
}
window.addEventListener('refresh-all-obsnotes', handleRefreshAll)
// Clean up listener when tool is deselected
const cleanup = () => {
window.removeEventListener('refresh-all-obsnotes', handleRefreshAll)
}
// Store cleanup function for later use
;(this as any).cleanup = cleanup
}
onExit() {
// Clean up event listeners
if ((this as any).cleanup) {
;(this as any).cleanup()
}
}
}

View File

@ -1,4 +1,4 @@
import { Editor, TLShape, Box } from "@tldraw/tldraw"
import { Editor, TLShape, Box, TLShapeId } from "@tldraw/tldraw"
/**
* Check if two boxes overlap
@ -20,8 +20,9 @@ function boxesOverlap(
* Get the bounding box of a shape
*/
function getShapeBounds(editor: Editor, shape: TLShape | string): Box | null {
const shapeId = typeof shape === 'string' ? shape : shape.id
return editor.getShapePageBounds(shapeId)
const shapeId = typeof shape === 'string' ? (shape as TLShapeId) : shape.id
const bounds = editor.getShapePageBounds(shapeId)
return bounds ?? null
}
/**
@ -70,7 +71,7 @@ export function resolveOverlaps(editor: Editor, shapeId: string): void {
const newY = shapeBox.y // Keep same Y position
editor.updateShape({
id: shapeId,
id: shapeId as TLShapeId,
type: shape.type,
x: newX,
y: newY,
@ -90,7 +91,7 @@ export function resolveOverlaps(editor: Editor, shapeId: string): void {
if (boxesOverlap(newShapeBox, otherBox, 20)) {
const newY2 = otherBox.y + otherBox.h + 20
editor.updateShape({
id: shapeId,
id: shapeId as TLShapeId,
type: shape.type,
x: shapeBox.x, // Keep original X
y: newY2,

View File

@ -60,5 +60,6 @@ echo " npm run dev"

View File

@ -562,7 +562,7 @@ const router = AutoRouter<IRequest, [env: Environment, ctx: ExecutionContext]>({
})
}
const data = await response.json()
const data = await response.json() as { data?: any[] }
console.log('Fathom API success, data length:', data?.data?.length || 0)
return new Response(JSON.stringify(data), {
headers: { 'Content-Type': 'application/json' }