@parcae/model
Advanced tools
| import { proxy } from 'valtio'; | ||
| // src/adapters/client.ts | ||
| function stripVersion(path) { | ||
| return path.replace(/^\/v\d+/, ""); | ||
| } | ||
| var FrontendAdapter = class { | ||
| transport; | ||
| constructor(transport) { | ||
| this.transport = transport; | ||
| } | ||
| p(modelPath) { | ||
| return stripVersion(modelPath); | ||
| } | ||
| // ── createStore ────────────────────────────────────────────────────── | ||
| createStore(data) { | ||
| return proxy(data); | ||
| } | ||
| // ── save ───────────────────────────────────────────────────────────── | ||
| async save(model, changes) { | ||
| const ModelClass = model.constructor; | ||
| const path = this.resolvePath(ModelClass); | ||
| if (changes.creating) { | ||
| const result = await this.transport.post(path, model.__data); | ||
| if (result?.id) model.__data.id = result.id; | ||
| } else if (changes.ops.length > 0) { | ||
| await this.transport.patch(`${path}/${model.id}`, { ops: changes.ops }); | ||
| } else if (changes.updates.length > 0) { | ||
| const data = {}; | ||
| for (const key of changes.updates) { | ||
| data[key] = model.__data[key]; | ||
| } | ||
| await this.transport.put(`${path}/${model.id}`, data); | ||
| } | ||
| } | ||
| // ── remove ─────────────────────────────────────────────────────────── | ||
| async remove(model) { | ||
| const ModelClass = model.constructor; | ||
| const path = this.resolvePath(ModelClass); | ||
| await this.transport.delete(`${path}/${model.id}`); | ||
| } | ||
| // ── findById ───────────────────────────────────────────────────────── | ||
| async findById(modelClass, id) { | ||
| const path = this.resolvePath(modelClass); | ||
| try { | ||
| const data = await this.transport.get(`${path}/${id}`); | ||
| if (!data) return null; | ||
| return new modelClass(this, data); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| // ── query ──────────────────────────────────────────────────────────── | ||
| query(modelClass) { | ||
| return this._buildQuery(modelClass, []); | ||
| } | ||
| _buildQuery(modelClass, steps) { | ||
| const adapter = this; | ||
| const CHAINABLE = [ | ||
| "select", | ||
| "where", | ||
| "andWhere", | ||
| "orWhere", | ||
| "whereIn", | ||
| "whereNot", | ||
| "whereNotIn", | ||
| "whereNull", | ||
| "whereNotNull", | ||
| "whereBetween", | ||
| "whereRaw", | ||
| "orWhereRaw", | ||
| "orWhereIn", | ||
| "orWhereNull", | ||
| "whereExists", | ||
| "orderBy", | ||
| "orderByRaw", | ||
| "groupBy", | ||
| "groupByRaw", | ||
| "having", | ||
| "havingRaw", | ||
| "limit", | ||
| "offset", | ||
| "distinct", | ||
| "distinctOn", | ||
| "join", | ||
| "innerJoin", | ||
| "leftJoin", | ||
| "rightJoin", | ||
| "clearOrder", | ||
| "clearSelect", | ||
| "from", | ||
| "sum", | ||
| "avg", | ||
| "min", | ||
| "max", | ||
| "increment", | ||
| "decrement" | ||
| ]; | ||
| const chain = {}; | ||
| for (const method of CHAINABLE) { | ||
| chain[method] = (...args) => { | ||
| return adapter._buildQuery(modelClass, [ | ||
| ...steps, | ||
| { method, args: adapter._serializeArgs(args) } | ||
| ]); | ||
| }; | ||
| } | ||
| chain.basic = (limit = 25, sort = "createdAt", direction = "desc", page = 0) => { | ||
| return adapter._buildQuery(modelClass, [ | ||
| ...steps, | ||
| { method: "orderBy", args: [sort, direction] }, | ||
| { method: "limit", args: [limit] }, | ||
| { method: "offset", args: [page * limit] } | ||
| ]); | ||
| }; | ||
| let debounceMs = void 0; | ||
| chain.debounce = (ms) => { | ||
| debounceMs = ms; | ||
| const newChain = adapter._buildQuery(modelClass, steps); | ||
| newChain.__debounceMs = ms; | ||
| return newChain; | ||
| }; | ||
| chain.find = async () => { | ||
| const path = adapter.resolvePath(modelClass); | ||
| const result = await adapter.transport.get(path, { __query: steps }); | ||
| const items = result?.[modelClass.type + "s"] ?? result?.items ?? []; | ||
| return items.map((row) => new modelClass(adapter, row)); | ||
| }; | ||
| chain.findAndSubscribe = async () => { | ||
| const path = adapter.resolvePath(modelClass); | ||
| const result = await adapter.transport.get(path, { | ||
| __query: steps, | ||
| __subscribe: true | ||
| }); | ||
| const items = result?.[modelClass.type + "s"] ?? result?.items ?? []; | ||
| return { | ||
| items: items.map((row) => new modelClass(adapter, row)), | ||
| hash: result?.__hash ?? null | ||
| }; | ||
| }; | ||
| chain.first = async () => { | ||
| const all = await chain.find(); | ||
| return all[0] ?? null; | ||
| }; | ||
| chain.count = async () => { | ||
| const path = adapter.resolvePath(modelClass); | ||
| const result = await adapter.transport.get(path, { | ||
| __query: steps, | ||
| __count: true | ||
| }); | ||
| return result?.total ?? 0; | ||
| }; | ||
| chain.__steps = steps; | ||
| chain.__modelType = modelClass.type; | ||
| chain.__modelClass = modelClass; | ||
| chain.__adapter = adapter; | ||
| Object.defineProperty(chain, "__debounceMs", { | ||
| get: () => debounceMs, | ||
| enumerable: true | ||
| }); | ||
| return chain; | ||
| } | ||
| _serializeArgs(args) { | ||
| return args.map((arg) => { | ||
| if (typeof arg === "function") return "__fn__"; | ||
| return arg; | ||
| }); | ||
| } | ||
| // ── patch ──────────────────────────────────────────────────────────── | ||
| async patch(model, ops) { | ||
| const ModelClass = model.constructor; | ||
| const path = this.resolvePath(ModelClass); | ||
| await this.transport.patch(`${path}/${model.id}`, { ops }); | ||
| } | ||
| // ── helpers ────────────────────────────────────────────────────────── | ||
| resolvePath(modelClass) { | ||
| if (!modelClass.path && !modelClass.type) { | ||
| throw new Error(`Model has no path or type`); | ||
| } | ||
| const fullPath = modelClass.path ?? `/v1/${modelClass.type}s`; | ||
| return this.p(fullPath); | ||
| } | ||
| }; | ||
| var client_default = FrontendAdapter; | ||
| export { FrontendAdapter, client_default }; | ||
| //# sourceMappingURL=chunk-UE7DW2FG.js.map | ||
| //# sourceMappingURL=chunk-UE7DW2FG.js.map |
| {"version":3,"sources":["../src/adapters/client.ts"],"names":[],"mappings":";;;AAwFA,SAAS,aAAa,IAAA,EAAsB;AAC1C,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA;AACnC;AAIO,IAAM,kBAAN,MAA8C;AAAA,EAC5C,SAAA;AAAA,EAEP,YAAY,SAAA,EAAsB;AAChC,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACnB;AAAA,EAEQ,EAAE,SAAA,EAA2B;AACnC,IAAA,OAAO,aAAa,SAAS,CAAA;AAAA,EAC/B;AAAA;AAAA,EAIA,YAAY,IAAA,EAAgD;AAC1D,IAAA,OAAO,MAAM,IAAI,CAAA;AAAA,EACnB;AAAA;AAAA,EAIA,MAAM,IAAA,CAAK,KAAA,EAAY,OAAA,EAAmC;AACxD,IAAA,MAAM,aAAa,KAAA,CAAM,WAAA;AACzB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,UAAU,CAAA;AAExC,IAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,UAAU,IAAA,CAAK,IAAA,EAAM,MAAM,MAAM,CAAA;AAC3D,MAAA,IAAI,MAAA,EAAQ,EAAA,EAAI,KAAA,CAAM,MAAA,CAAO,KAAK,MAAA,CAAO,EAAA;AAAA,IAC3C,CAAA,MAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,MAAA,GAAS,CAAA,EAAG;AACjC,MAAA,MAAM,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAA,CAAM,EAAE,CAAA,CAAA,EAAI,EAAE,GAAA,EAAK,OAAA,CAAQ,KAAK,CAAA;AAAA,IACxE,CAAA,MAAA,IAAW,OAAA,CAAQ,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACrC,MAAA,MAAM,OAA4B,EAAC;AACnC,MAAA,KAAA,MAAW,GAAA,IAAO,QAAQ,OAAA,EAAS;AACjC,QAAA,IAAA,CAAK,GAAG,CAAA,GAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAA;AAAA,MAC9B;AACA,MAAA,MAAM,IAAA,CAAK,UAAU,GAAA,CAAI,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAA,CAAM,EAAE,CAAA,CAAA,EAAI,IAAI,CAAA;AAAA,IACtD;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,OAAO,KAAA,EAA2B;AACtC,IAAA,MAAM,aAAa,KAAA,CAAM,WAAA;AACzB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,UAAU,CAAA;AACxC,IAAA,MAAM,IAAA,CAAK,UAAU,MAAA,CAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAA,CAAM,EAAE,CAAA,CAAE,CAAA;AAAA,EACnD;AAAA;AAAA,EAIA,MAAM,QAAA,CACJ,UAAA,EACA,EAAA,EACmB;AACnB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,UAAU,CAAA;AACxC,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAA;AACrD,MAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,MAAA,OAAO,IAAI,UAAA,CAAW,IAAA,EAAM,IAAI,CAAA;AAAA,IAClC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAIA,MAAS,UAAA,EAAgD;AACvD,IAAA,OAAO,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY,EAAE,CAAA;AAAA,EACxC;AAAA,EAEQ,WAAA,CACN,YACA,KAAA,EACe;AACf,IAAA,MAAM,OAAA,GAAU,IAAA;AAEhB,IAAA,MAAM,SAAA,GAAY;AAAA,MAChB,QAAA;AAAA,MACA,OAAA;AAAA,MACA,UAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA;AAAA,MACA,UAAA;AAAA,MACA,YAAA;AAAA,MACA,WAAA;AAAA,MACA,cAAA;AAAA,MACA,cAAA;AAAA,MACA,UAAA;AAAA,MACA,YAAA;AAAA,MACA,WAAA;AAAA,MACA,aAAA;AAAA,MACA,aAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA,UAAA;AAAA,MACA,YAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,MACA,YAAA;AAAA,MACA,aAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA;AAAA,MACA,KAAA;AAAA,MACA,KAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,MAAM,QAAa,EAAC;AAEpB,IAAA,KAAA,MAAW,UAAU,SAAA,EAAW;AAC9B,MAAA,KAAA,CAAM,MAAM,CAAA,GAAI,CAAA,GAAI,IAAA,KAAgB;AAClC,QAAA,OAAO,OAAA,CAAQ,YAAY,UAAA,EAAY;AAAA,UACrC,GAAG,KAAA;AAAA,UACH,EAAE,MAAA,EAAQ,IAAA,EAAM,OAAA,CAAQ,cAAA,CAAe,IAAI,CAAA;AAAE,SAC9C,CAAA;AAAA,MACH,CAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM,KAAA,GAAQ,CACZ,KAAA,GAAgB,EAAA,EAChB,OAAe,WAAA,EACf,SAAA,GAA4B,MAAA,EAC5B,IAAA,GAAe,CAAA,KACZ;AACH,MAAA,OAAO,OAAA,CAAQ,YAAY,UAAA,EAAY;AAAA,QACrC,GAAG,KAAA;AAAA,QACH,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAM,CAAC,IAAA,EAAM,SAAS,CAAA,EAAE;AAAA,QAC7C,EAAE,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,CAAC,KAAK,CAAA,EAAE;AAAA,QACjC,EAAE,MAAA,EAAQ,QAAA,EAAU,MAAM,CAAC,IAAA,GAAO,KAAK,CAAA;AAAE,OAC1C,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,IAAI,UAAA,GAAiC,MAAA;AACrC,IAAA,KAAA,CAAM,QAAA,GAAW,CAAC,EAAA,KAAe;AAC/B,MAAA,UAAA,GAAa,EAAA;AACb,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,WAAA,CAAY,UAAA,EAAY,KAAK,CAAA;AACtD,MAAC,SAAiB,YAAA,GAAe,EAAA;AACjC,MAAA,OAAO,QAAA;AAAA,IACT,CAAA;AAEA,IAAA,KAAA,CAAM,OAAO,YAA0B;AACrC,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,WAAA,CAAY,UAAU,CAAA;AAC3C,MAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,SAAA,CAAU,IAAI,IAAA,EAAM,EAAE,OAAA,EAAS,KAAA,EAAO,CAAA;AACnE,MAAA,MAAM,KAAA,GAAQ,SAAS,UAAA,CAAW,IAAA,GAAO,GAAG,CAAA,IAAK,MAAA,EAAQ,SAAS,EAAC;AACnE,MAAA,OAAO,KAAA,CAAM,IAAI,CAAC,GAAA,KAAa,IAAI,UAAA,CAAW,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA,IAC7D,CAAA;AAMA,IAAA,KAAA,CAAM,mBAAmB,YAGnB;AACJ,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,WAAA,CAAY,UAAU,CAAA;AAC3C,MAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,SAAA,CAAU,IAAI,IAAA,EAAM;AAAA,QAC/C,OAAA,EAAS,KAAA;AAAA,QACT,WAAA,EAAa;AAAA,OACd,CAAA;AACD,MAAA,MAAM,KAAA,GAAQ,SAAS,UAAA,CAAW,IAAA,GAAO,GAAG,CAAA,IAAK,MAAA,EAAQ,SAAS,EAAC;AACnE,MAAA,OAAO;AAAA,QACL,KAAA,EAAO,MAAM,GAAA,CAAI,CAAC,QAAa,IAAI,UAAA,CAAW,OAAA,EAAS,GAAG,CAAC,CAAA;AAAA,QAC3D,IAAA,EAAM,QAAQ,MAAA,IAAU;AAAA,OAC1B;AAAA,IACF,CAAA;AAEA,IAAA,KAAA,CAAM,QAAQ,YAA+B;AAC3C,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,EAAK;AAC7B,MAAA,OAAO,GAAA,CAAI,CAAC,CAAA,IAAK,IAAA;AAAA,IACnB,CAAA;AAEA,IAAA,KAAA,CAAM,QAAQ,YAA6B;AACzC,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,WAAA,CAAY,UAAU,CAAA;AAC3C,MAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,SAAA,CAAU,IAAI,IAAA,EAAM;AAAA,QAC/C,OAAA,EAAS,KAAA;AAAA,QACT,OAAA,EAAS;AAAA,OACV,CAAA;AACD,MAAA,OAAO,QAAQ,KAAA,IAAS,CAAA;AAAA,IAC1B,CAAA;AAEA,IAAA,KAAA,CAAM,OAAA,GAAU,KAAA;AAChB,IAAA,KAAA,CAAM,cAAc,UAAA,CAAW,IAAA;AAC/B,IAAA,KAAA,CAAM,YAAA,GAAe,UAAA;AACrB,IAAA,KAAA,CAAM,SAAA,GAAY,OAAA;AAClB,IAAA,MAAA,CAAO,cAAA,CAAe,OAAO,cAAA,EAAgB;AAAA,MAC3C,KAAK,MAAM,UAAA;AAAA,MACX,UAAA,EAAY;AAAA,KACb,CAAA;AAED,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEQ,eAAe,IAAA,EAAoB;AACzC,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,KAAQ;AACvB,MAAA,IAAI,OAAO,GAAA,KAAQ,UAAA,EAAY,OAAO,QAAA;AACtC,MAAA,OAAO,GAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAIA,MAAM,KAAA,CAAM,KAAA,EAAY,GAAA,EAA+B;AACrD,IAAA,MAAM,aAAa,KAAA,CAAM,WAAA;AACzB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,UAAU,CAAA;AACxC,IAAA,MAAM,IAAA,CAAK,SAAA,CAAU,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAA,CAAM,EAAE,CAAA,CAAA,EAAI,EAAE,GAAA,EAAK,CAAA;AAAA,EAC3D;AAAA;AAAA,EAIQ,YAAY,UAAA,EAAsC;AACxD,IAAA,IAAI,CAAC,UAAA,CAAW,IAAA,IAAQ,CAAC,WAAW,IAAA,EAAM;AACxC,MAAA,MAAM,IAAI,MAAM,CAAA,yBAAA,CAA2B,CAAA;AAAA,IAC7C;AACA,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,IAAA,IAAQ,CAAA,IAAA,EAAO,WAAW,IAAI,CAAA,CAAA,CAAA;AAC1D,IAAA,OAAO,IAAA,CAAK,EAAE,QAAQ,CAAA;AAAA,EACxB;AACF;AAEA,IAAO,cAAA,GAAQ","file":"chunk-UE7DW2FG.js","sourcesContent":["/**\n * FrontendAdapter — Valtio + Transport for Parcae Model.\n *\n * Transport-agnostic. Works with any implementation of the Transport interface:\n * - SocketTransport (Socket.IO — bidirectional, realtime)\n * - SSETransport (Server-Sent Events — read-heavy, simpler)\n * - GRPCTransport (gRPC — service-to-service)\n * - Or any custom transport\n */\n\nimport { proxy } from \"valtio\";\nimport type {\n ModelAdapter,\n ModelConstructor,\n ChangeSet,\n QueryChain,\n QueryStep,\n PatchOp,\n} from \"./types\";\n\n// ─── Transport Interface ─────────────────────────────────────────────────────\n\n/**\n * Abstract transport layer. Decouples the Model system from the wire protocol.\n *\n * Implementations:\n * - SocketTransport: Socket.IO (bidirectional, realtime subscriptions)\n * - SSETransport: HTTP + Server-Sent Events (read-heavy, simpler infra)\n * - GRPCTransport: gRPC (service-to-service, protobuf)\n */\nexport interface Transport {\n // ── Request/Response (RPC-style) ────────────────────────────────────\n get(path: string, data?: any): Promise<any>;\n post(path: string, data?: any): Promise<any>;\n put(path: string, data?: any): Promise<any>;\n patch(path: string, data?: any): Promise<any>;\n delete(path: string, data?: any): Promise<any>;\n\n // ── Subscriptions (realtime) ────────────────────────────────────────\n /**\n * Subscribe to a named event stream.\n * Returns a dispose function to unsubscribe.\n *\n * Socket.IO: socket.on(event, handler)\n * SSE: new EventSource(url) per channel\n * gRPC: server streaming RPC\n */\n subscribe?(event: string, handler: (...args: any[]) => void): () => void;\n\n /**\n * Unsubscribe from a named event stream.\n * Alternative to calling the dispose function returned by subscribe().\n */\n unsubscribe?(event: string, handler?: (...args: any[]) => void): void;\n\n // ── Control messages ────────────────────────────────────────────────\n /**\n * Send a control message to the server (fire-and-forget).\n *\n * Socket.IO: socket.emit(event, ...args)\n * SSE: POST /v1/__control { event, args }\n * gRPC: unary RPC\n */\n send?(event: string, ...args: any[]): void;\n\n // ── Connection state ────────────────────────────────────────────────\n /** Whether the transport is currently connected. */\n readonly isConnected?: boolean;\n /** Whether the transport is currently loading/connecting. */\n readonly isLoading?: boolean;\n\n /**\n * Listen for connection state changes.\n * Events: \"connected\", \"disconnected\", \"reconnecting\", \"error\"\n */\n on?(event: string, handler: (...args: any[]) => void): void;\n off?(event: string, handler?: (...args: any[]) => void): void;\n\n /** Disconnect the transport. */\n disconnect?(): void;\n /** Reconnect the transport. */\n reconnect?(): Promise<void>;\n}\n\n/**\n * Strip version prefix from a path if it starts with /v{number}.\n * The transport prepends the version automatically.\n */\nfunction stripVersion(path: string): string {\n return path.replace(/^\\/v\\d+/, \"\");\n}\n\n// ─── FrontendAdapter ─────────────────────────────────────────────────────────\n\nexport class FrontendAdapter implements ModelAdapter {\n public transport: Transport;\n\n constructor(transport: Transport) {\n this.transport = transport;\n }\n\n private p(modelPath: string): string {\n return stripVersion(modelPath);\n }\n\n // ── createStore ──────────────────────────────────────────────────────\n\n createStore(data: Record<string, any>): Record<string, any> {\n return proxy(data);\n }\n\n // ── save ─────────────────────────────────────────────────────────────\n\n async save(model: any, changes: ChangeSet): Promise<void> {\n const ModelClass = model.constructor as ModelConstructor;\n const path = this.resolvePath(ModelClass);\n\n if (changes.creating) {\n const result = await this.transport.post(path, model.__data);\n if (result?.id) model.__data.id = result.id;\n } else if (changes.ops.length > 0) {\n await this.transport.patch(`${path}/${model.id}`, { ops: changes.ops });\n } else if (changes.updates.length > 0) {\n const data: Record<string, any> = {};\n for (const key of changes.updates) {\n data[key] = model.__data[key];\n }\n await this.transport.put(`${path}/${model.id}`, data);\n }\n }\n\n // ── remove ───────────────────────────────────────────────────────────\n\n async remove(model: any): Promise<void> {\n const ModelClass = model.constructor as ModelConstructor;\n const path = this.resolvePath(ModelClass);\n await this.transport.delete(`${path}/${model.id}`);\n }\n\n // ── findById ─────────────────────────────────────────────────────────\n\n async findById<T>(\n modelClass: ModelConstructor<T>,\n id: string,\n ): Promise<T | null> {\n const path = this.resolvePath(modelClass);\n try {\n const data = await this.transport.get(`${path}/${id}`);\n if (!data) return null;\n return new modelClass(this, data) as T;\n } catch {\n return null;\n }\n }\n\n // ── query ────────────────────────────────────────────────────────────\n\n query<T>(modelClass: ModelConstructor<T>): QueryChain<T> {\n return this._buildQuery(modelClass, []);\n }\n\n private _buildQuery<T>(\n modelClass: ModelConstructor<T>,\n steps: QueryStep[],\n ): QueryChain<T> {\n const adapter = this;\n\n const CHAINABLE = [\n \"select\",\n \"where\",\n \"andWhere\",\n \"orWhere\",\n \"whereIn\",\n \"whereNot\",\n \"whereNotIn\",\n \"whereNull\",\n \"whereNotNull\",\n \"whereBetween\",\n \"whereRaw\",\n \"orWhereRaw\",\n \"orWhereIn\",\n \"orWhereNull\",\n \"whereExists\",\n \"orderBy\",\n \"orderByRaw\",\n \"groupBy\",\n \"groupByRaw\",\n \"having\",\n \"havingRaw\",\n \"limit\",\n \"offset\",\n \"distinct\",\n \"distinctOn\",\n \"join\",\n \"innerJoin\",\n \"leftJoin\",\n \"rightJoin\",\n \"clearOrder\",\n \"clearSelect\",\n \"from\",\n \"sum\",\n \"avg\",\n \"min\",\n \"max\",\n \"increment\",\n \"decrement\",\n ] as const;\n\n const chain: any = {};\n\n for (const method of CHAINABLE) {\n chain[method] = (...args: any[]) => {\n return adapter._buildQuery(modelClass, [\n ...steps,\n { method, args: adapter._serializeArgs(args) },\n ]);\n };\n }\n\n chain.basic = (\n limit: number = 25,\n sort: string = \"createdAt\",\n direction: \"asc\" | \"desc\" = \"desc\",\n page: number = 0,\n ) => {\n return adapter._buildQuery(modelClass, [\n ...steps,\n { method: \"orderBy\", args: [sort, direction] },\n { method: \"limit\", args: [limit] },\n { method: \"offset\", args: [page * limit] },\n ]);\n };\n\n let debounceMs: number | undefined = undefined;\n chain.debounce = (ms: number) => {\n debounceMs = ms;\n const newChain = adapter._buildQuery(modelClass, steps);\n (newChain as any).__debounceMs = ms;\n return newChain;\n };\n\n chain.find = async (): Promise<T[]> => {\n const path = adapter.resolvePath(modelClass);\n const result = await adapter.transport.get(path, { __query: steps });\n const items = result?.[modelClass.type + \"s\"] ?? result?.items ?? [];\n return items.map((row: any) => new modelClass(adapter, row));\n };\n\n /**\n * Like find(), but also subscribes to realtime updates.\n * Returns { items, hash } — the hash identifies the subscription.\n */\n chain.findAndSubscribe = async (): Promise<{\n items: T[];\n hash: string | null;\n }> => {\n const path = adapter.resolvePath(modelClass);\n const result = await adapter.transport.get(path, {\n __query: steps,\n __subscribe: true,\n });\n const items = result?.[modelClass.type + \"s\"] ?? result?.items ?? [];\n return {\n items: items.map((row: any) => new modelClass(adapter, row)),\n hash: result?.__hash ?? null,\n };\n };\n\n chain.first = async (): Promise<T | null> => {\n const all = await chain.find();\n return all[0] ?? null;\n };\n\n chain.count = async (): Promise<number> => {\n const path = adapter.resolvePath(modelClass);\n const result = await adapter.transport.get(path, {\n __query: steps,\n __count: true,\n });\n return result?.total ?? 0;\n };\n\n chain.__steps = steps;\n chain.__modelType = modelClass.type;\n chain.__modelClass = modelClass;\n chain.__adapter = adapter;\n Object.defineProperty(chain, \"__debounceMs\", {\n get: () => debounceMs,\n enumerable: true,\n });\n\n return chain as QueryChain<T>;\n }\n\n private _serializeArgs(args: any[]): any[] {\n return args.map((arg) => {\n if (typeof arg === \"function\") return \"__fn__\";\n return arg;\n });\n }\n\n // ── patch ────────────────────────────────────────────────────────────\n\n async patch(model: any, ops: PatchOp[]): Promise<void> {\n const ModelClass = model.constructor as ModelConstructor;\n const path = this.resolvePath(ModelClass);\n await this.transport.patch(`${path}/${model.id}`, { ops });\n }\n\n // ── helpers ──────────────────────────────────────────────────────────\n\n private resolvePath(modelClass: ModelConstructor): string {\n if (!modelClass.path && !modelClass.type) {\n throw new Error(`Model has no path or type`);\n }\n const fullPath = modelClass.path ?? `/v1/${modelClass.type}s`;\n return this.p(fullPath);\n }\n}\n\nexport default FrontendAdapter;\n"]} |
@@ -1,3 +0,3 @@ | ||
| export { FrontendAdapter, client_default as default } from '../chunk-CHRGDH3V.js'; | ||
| export { FrontendAdapter, client_default as default } from '../chunk-UE7DW2FG.js'; | ||
| //# sourceMappingURL=client.js.map | ||
| //# sourceMappingURL=client.js.map |
@@ -144,2 +144,7 @@ import { Operation } from 'fast-json-patch'; | ||
| find(): Promise<T[]>; | ||
| /** Like find(), but also subscribes to realtime updates via the QSM. */ | ||
| findAndSubscribe(): Promise<{ | ||
| items: T[]; | ||
| hash: string | null; | ||
| }>; | ||
| first(): Promise<T | null>; | ||
@@ -146,0 +151,0 @@ count(): Promise<number>; |
+2
-5
@@ -1,2 +0,2 @@ | ||
| export { FrontendAdapter } from './chunk-CHRGDH3V.js'; | ||
| export { FrontendAdapter } from './chunk-UE7DW2FG.js'; | ||
| import { EventEmitter } from 'eventemitter3'; | ||
@@ -83,6 +83,2 @@ import ShortId from 'short-unique-id'; | ||
| const adapter = Model.hasAdapter() ? Model.getAdapter() : await Model.waitForAdapter(); | ||
| console.log( | ||
| "[parcae/model] lazy resolve: got adapter, building chain for", | ||
| modelClass.type | ||
| ); | ||
| let q = adapter.query(modelClass); | ||
@@ -95,2 +91,3 @@ for (const step of steps) { | ||
| chain.find = async () => (await resolve()).find(); | ||
| chain.findAndSubscribe = async () => (await resolve()).findAndSubscribe(); | ||
| chain.first = async () => (await resolve()).first(); | ||
@@ -97,0 +94,0 @@ chain.count = async () => (await resolve()).count(); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/Model.ts"],"names":["target"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @parcae/model — Model Base Class\n *\n * The instance IS the data store. No separate __data object.\n * A Proxy wraps the instance for change tracking and ref resolution.\n * Class property defaults (title = \"\", published = false) work naturally\n * because they set directly on the instance which the Proxy intercepts.\n *\n * Internal state uses Symbol keys to avoid collisions with data properties.\n */\n\nimport { EventEmitter } from \"eventemitter3\";\nimport ShortId from \"short-unique-id\";\nimport { applyPatch } from \"fast-json-patch\";\nimport type {\n ModelAdapter,\n ModelConstructor,\n ChangeSet,\n QueryChain,\n SchemaDefinition,\n PatchOp,\n} from \"./adapters/types\";\n\n// ─── ID Generation ───────────────────────────────────────────────────────────\n\nconst uid = new ShortId({ length: 20 });\n\nexport function generateId(): string {\n return uid.rnd();\n}\n\n// ─── Symbols for internal state (never collide with data properties) ─────────\n\nconst SYM_ADAPTER = Symbol(\"parcae:adapter\");\nconst SYM_UPDATES = Symbol(\"parcae:updates\");\nconst SYM_PATCHING = Symbol(\"parcae:patching\");\nconst SYM_IS_NEW = Symbol(\"parcae:isNew\");\nconst SYM_SAVE_TIMER = Symbol(\"parcae:saveTimer\");\nconst SYM_DEBOUNCE = Symbol(\"parcae:debounceMs\");\nconst SYM_IS_PROXY = Symbol(\"parcae:isProxy\");\nconst SYM_INIT_DATA = Symbol(\"parcae:initData\");\n\n// ─── Keys that should NOT be treated as data ─────────────────────────────────\n\nconst INSTANCE_METHODS = new Set([\n \"save\",\n \"patch\",\n \"remove\",\n \"refresh\",\n \"load\",\n \"sanitize\",\n \"toJSON\",\n \"_flush\",\n \"_createRefProxy\",\n \"constructor\",\n]);\n\n// ─── Lazy Query Chain ────────────────────────────────────────────────────────\n// Records query steps without needing an adapter. The adapter is resolved\n// lazily when a terminal method (.find(), .first(), .count()) is called.\n// This allows building queries before Model.use() is called (e.g. in React\n// component bodies before ParcaeProvider mounts).\n\nfunction lazyQuery<T>(\n modelClass: ModelConstructor<T>,\n steps: any[] = [],\n): QueryChain<T> {\n const CHAINABLE = [\n \"select\",\n \"where\",\n \"andWhere\",\n \"orWhere\",\n \"whereIn\",\n \"whereNot\",\n \"whereNotIn\",\n \"whereNull\",\n \"whereNotNull\",\n \"whereBetween\",\n \"whereRaw\",\n \"orWhereRaw\",\n \"orWhereIn\",\n \"orWhereNull\",\n \"whereExists\",\n \"orderBy\",\n \"orderByRaw\",\n \"groupBy\",\n \"groupByRaw\",\n \"having\",\n \"havingRaw\",\n \"limit\",\n \"offset\",\n \"distinct\",\n \"distinctOn\",\n \"join\",\n \"innerJoin\",\n \"leftJoin\",\n \"rightJoin\",\n \"clearOrder\",\n \"clearSelect\",\n \"from\",\n \"sum\",\n \"avg\",\n \"min\",\n \"max\",\n \"increment\",\n \"decrement\",\n ] as const;\n\n const chain: any = {};\n\n for (const method of CHAINABLE) {\n chain[method] = (...args: any[]) =>\n lazyQuery(modelClass, [...steps, { method, args }]);\n }\n\n chain.basic = (\n limit = 25,\n sort = \"createdAt\",\n direction: \"asc\" | \"desc\" = \"desc\",\n page = 0,\n ) =>\n lazyQuery(modelClass, [\n ...steps,\n { method: \"orderBy\", args: [sort, direction] },\n { method: \"limit\", args: [limit] },\n { method: \"offset\", args: [page * limit] },\n ]);\n\n // Terminal methods — resolve adapter here (async, waits if not set yet)\n const resolve = async (): Promise<QueryChain<T>> => {\n const adapter = Model.hasAdapter()\n ? Model.getAdapter()\n : await Model.waitForAdapter();\n console.log(\n \"[parcae/model] lazy resolve: got adapter, building chain for\",\n modelClass.type,\n );\n let q = adapter.query(modelClass);\n for (const step of steps) {\n q = (q as any)[step.method](...step.args);\n }\n return q;\n };\n\n chain.find = async () => (await resolve()).find();\n chain.first = async () => (await resolve()).first();\n chain.count = async () => (await resolve()).count();\n\n // Internal metadata\n chain.__steps = steps;\n chain.__modelType = modelClass.type;\n chain.__modelClass = modelClass;\n chain.__adapter = null; // resolved lazily\n\n return chain as QueryChain<T>;\n}\n\n// ─── Keys ────────────────────────────────────────────────────────────────────\n\nconst EVENTEMITTER_KEYS = new Set([\n \"emit\",\n \"on\",\n \"off\",\n \"once\",\n \"removeListener\",\n \"removeAllListeners\",\n \"listeners\",\n \"listenerCount\",\n \"addListener\",\n \"eventNames\",\n \"_events\",\n \"_eventsCount\",\n]);\n\n/** Properties that are part of the data but handled specially. */\nconst SYSTEM_DATA_KEYS = new Set([\"id\", \"type\", \"createdAt\", \"updatedAt\"]);\n\n// ─── Model Class ─────────────────────────────────────────────────────────────\n\nexport class Model extends EventEmitter {\n // ── Static ─────────────────────────────────────────────────────────\n\n static type: string = \"\";\n static path?: string;\n static scope?: {\n read?: (ctx: any) => any;\n create?: (ctx: any) => any;\n update?: (ctx: any) => any;\n delete?: (ctx: any) => any;\n patch?: (ctx: any) => any;\n };\n static indexes?: (string | string[])[];\n static managed: boolean = true;\n /** @internal */\n static __schema?: SchemaDefinition;\n\n // Adapter lives on globalThis so it works across multiple copies of @parcae/model\n // (pnpm can install multiple versions — they all need to share the same adapter)\n private static get __adapter(): ModelAdapter | null {\n return (globalThis as any).__parcae_adapter ?? null;\n }\n private static set __adapter(v: ModelAdapter | null) {\n (globalThis as any).__parcae_adapter = v;\n }\n private static get __pendingAdapter(): Promise<ModelAdapter> | null {\n return (globalThis as any).__parcae_pending ?? null;\n }\n private static set __pendingAdapter(v: Promise<ModelAdapter> | null) {\n (globalThis as any).__parcae_pending = v;\n }\n private static get __resolveAdapter():\n | ((adapter: ModelAdapter) => void)\n | null {\n return (globalThis as any).__parcae_resolve ?? null;\n }\n private static set __resolveAdapter(\n v: ((adapter: ModelAdapter) => void) | null,\n ) {\n (globalThis as any).__parcae_resolve = v;\n }\n\n static use(adapter: ModelAdapter): void {\n Model.__adapter = adapter;\n if (Model.__resolveAdapter) {\n Model.__resolveAdapter(adapter);\n Model.__resolveAdapter = null;\n Model.__pendingAdapter = null;\n }\n }\n\n static getAdapter(): ModelAdapter {\n if (!Model.__adapter) {\n throw new Error(\n \"No adapter set. Call Model.use(adapter) before using models.\",\n );\n }\n return Model.__adapter;\n }\n\n static hasAdapter(): boolean {\n return Model.__adapter !== null;\n }\n\n static waitForAdapter(): Promise<ModelAdapter> {\n if (Model.__adapter) return Promise.resolve(Model.__adapter);\n if (!Model.__pendingAdapter) {\n Model.__pendingAdapter = new Promise<ModelAdapter>((resolve) => {\n Model.__resolveAdapter = resolve;\n });\n }\n return Model.__pendingAdapter;\n }\n\n // ── Static Query Methods ───────────────────────────────────────────\n //\n // These build lazy query chains that only resolve the adapter at\n // execution time (.find(), .first(), .count()). This allows you to\n // build queries before the adapter is set (e.g. in React component\n // bodies before the ParcaeProvider mounts).\n\n /** Build a lazy query chain for this model class. */\n private static _query<T extends Model>(\n this: ModelConstructor<T>,\n ): QueryChain<T> {\n const ModelClass = this;\n return lazyQuery(ModelClass);\n }\n\n static create<T extends Model>(\n this: ModelConstructor<T>,\n data?: Record<string, any>,\n ): T {\n const instance = new this(Model.getAdapter(), {\n ...data,\n id: data?.id ?? generateId(),\n });\n (instance as any)[SYM_IS_NEW] = true;\n return instance;\n }\n\n static findById<T extends Model>(\n this: ModelConstructor<T>,\n id: string,\n ): Promise<T | null> {\n return Model.getAdapter().findById(this, id);\n }\n\n static where<T extends Model>(\n this: ModelConstructor<T>,\n ...args: any[]\n ): QueryChain<T> {\n return (this as any)._query().where(...args);\n }\n\n static whereRaw<T extends Model>(\n this: ModelConstructor<T>,\n query: string,\n ...bindings: any[]\n ): QueryChain<T> {\n return (this as any)._query().whereRaw(query, ...bindings);\n }\n\n static whereIn<T extends Model>(\n this: ModelConstructor<T>,\n column: string,\n values: any[],\n ): QueryChain<T> {\n return (this as any)._query().whereIn(column, values);\n }\n\n static whereNot<T extends Model>(\n this: ModelConstructor<T>,\n ...args: any[]\n ): QueryChain<T> {\n return (this as any)._query().whereNot(...args);\n }\n\n static whereNotIn<T extends Model>(\n this: ModelConstructor<T>,\n column: string,\n values: any[],\n ): QueryChain<T> {\n return (this as any)._query().whereNotIn(column, values);\n }\n\n static select<T extends Model>(\n this: ModelConstructor<T>,\n ...columns: string[]\n ): QueryChain<T> {\n return (this as any)._query().select(...columns);\n }\n\n static count<T extends Model>(this: ModelConstructor<T>): Promise<number> {\n return (this as any)._query().count();\n }\n\n static basic<T extends Model>(\n this: ModelConstructor<T>,\n limit?: number,\n sort?: string,\n direction?: \"asc\" | \"desc\",\n page?: number,\n ): QueryChain<T> {\n return (this as any)._query().basic(limit, sort, direction, page);\n }\n\n // ── Constructor ────────────────────────────────────────────────────\n\n constructor(adapter: ModelAdapter, data?: Record<string, any>) {\n super();\n\n // Set internal state via symbols (invisible to data property access)\n this[SYM_ADAPTER] = adapter;\n this[SYM_UPDATES] = [] as string[];\n this[SYM_PATCHING] = new Set<string>();\n this[SYM_IS_NEW] = false;\n this[SYM_SAVE_TIMER] = null;\n this[SYM_DEBOUNCE] = 0;\n this[SYM_IS_PROXY] = false;\n\n // Store the init data keys so the Proxy set trap knows which values\n // were explicitly provided (and shouldn't be overwritten by class\n // property defaults that run AFTER super() returns).\n const initDataKeys = new Set(data ? Object.keys(data) : []);\n this[SYM_INIT_DATA] = initDataKeys;\n\n // Set system data properties directly on the instance\n (this as any).id = data?.id ?? generateId();\n (this as any).type = (this.constructor as typeof Model).type;\n (this as any).createdAt = data?.createdAt ?? new Date().toISOString();\n (this as any).updatedAt = data?.updatedAt ?? new Date().toISOString();\n\n // Set all provided data on the instance BEFORE the Proxy wraps it.\n // These go directly on `this`, bypassing the Proxy.\n if (data) {\n for (const [key, value] of Object.entries(data)) {\n if (!SYSTEM_DATA_KEYS.has(key)) {\n (this as any)[key] = value;\n }\n }\n }\n\n // Return a Proxy for change tracking and ref resolution\n const proxy = new Proxy(this, {\n set(target, prop, value) {\n if (typeof prop === \"symbol\") {\n (target as any)[prop] = value;\n return true;\n }\n\n // EventEmitter internals — set directly, no tracking\n if (EVENTEMITTER_KEYS.has(prop)) {\n (target as any)[prop] = value;\n return true;\n }\n\n // Reference property — accept Model instance (extract ID) or raw value\n const schema = (target.constructor as typeof Model).__schema;\n if (schema && prop in schema) {\n const colDef = schema[prop];\n if (\n typeof colDef === \"object\" &&\n colDef !== null &&\n \"kind\" in colDef &&\n colDef.kind === \"ref\"\n ) {\n (target as any)[prop] =\n value instanceof Model ? (value as any).id : value;\n target[SYM_UPDATES].push(prop);\n return true;\n }\n }\n\n // $-prefixed write — raw ID for refs\n if (typeof prop === \"string\" && prop.startsWith(\"$\")) {\n const realKey = prop.slice(1);\n (target as any)[realKey] = value;\n target[SYM_UPDATES].push(realKey);\n return true;\n }\n\n // During construction (before SYM_IS_PROXY is set), class property\n // initializers fire. If this key was explicitly provided in the\n // constructor data, don't let the default overwrite it.\n if (!target[SYM_IS_PROXY] && target[SYM_INIT_DATA]?.has(prop)) {\n // Skip — the explicit value is already set on the instance\n return true;\n }\n\n // Regular data property — set on the instance, track the change\n (target as any)[prop] = value;\n\n // Only track changes for data properties (not during construction)\n if (\n target[SYM_IS_PROXY] &&\n !SYSTEM_DATA_KEYS.has(prop) &&\n !INSTANCE_METHODS.has(prop)\n ) {\n target[SYM_UPDATES].push(prop);\n }\n\n return true;\n },\n\n get(target, prop) {\n if (typeof prop === \"symbol\") {\n return (target as any)[prop];\n }\n\n // $-prefixed access — raw ID for reference properties\n if (typeof prop === \"string\" && prop.startsWith(\"$\")) {\n const realKey = prop.slice(1);\n return (target as any)[realKey];\n }\n\n // Reference property — return lazy-loading proxy\n const schema = (target.constructor as typeof Model).__schema;\n if (schema && prop in schema) {\n const colDef = schema[prop];\n if (\n typeof colDef === \"object\" &&\n colDef !== null &&\n \"kind\" in colDef &&\n colDef.kind === \"ref\"\n ) {\n const refId = (target as any)[prop];\n if (!refId) return null;\n return target._createRefProxy(colDef.target, refId);\n }\n }\n\n return (target as any)[prop];\n },\n\n has(target, prop) {\n return prop in target;\n },\n\n // Class field initializers use [[DefineOwnProperty]], not [[Set]].\n // This trap intercepts them so we can skip defaults for keys that\n // were explicitly provided in the constructor data.\n defineProperty(target, prop, descriptor) {\n if (typeof prop === \"symbol\") {\n return Reflect.defineProperty(target, prop, descriptor);\n }\n\n // During construction: if this key was in init data, skip the default\n if (\n !target[SYM_IS_PROXY] &&\n target[SYM_INIT_DATA]?.has(prop as string)\n ) {\n return true;\n }\n\n // EventEmitter internals — define directly\n if (EVENTEMITTER_KEYS.has(prop)) {\n return Reflect.defineProperty(target, prop, descriptor);\n }\n\n // Normal data property — define it (this is a class field default)\n return Reflect.defineProperty(target, prop, descriptor);\n },\n });\n\n // SYM_IS_PROXY starts false (set earlier). Property initializers from the\n // subclass run after this return, setting defaults on the proxy. The set\n // trap skips change tracking when SYM_IS_PROXY is false. After construction\n // completes, the first explicit write flips it to true via a lazy check.\n //\n // But we need a way to flip it. Use a microtask: by the time any user code\n // runs (which is async or at least after the constructor call), the\n // microtask will have fired.\n const target = this;\n queueMicrotask(() => {\n target[SYM_IS_PROXY] = true;\n delete (target as any)[SYM_INIT_DATA];\n });\n\n return proxy;\n }\n\n // ── Data Access (for adapters/serialization) ──────────────────────\n\n /**\n * Get all data properties as a plain object.\n * Used by adapters for serialization. Excludes methods, symbols, and EE internals.\n */\n get __data(): Record<string, any> {\n const data: Record<string, any> = {};\n for (const key of Object.keys(this)) {\n if (EVENTEMITTER_KEYS.has(key)) continue;\n if (INSTANCE_METHODS.has(key)) continue;\n if (key.startsWith(\"_\")) continue;\n data[key] = (this as any)[key];\n }\n return data;\n }\n\n /**\n * Set data properties from a plain object (used by adapters during hydration).\n */\n set __data(data: Record<string, any>) {\n for (const [key, value] of Object.entries(data)) {\n (this as any)[key] = value;\n }\n }\n\n /** @internal */\n get __updates(): string[] {\n return this[SYM_UPDATES];\n }\n set __updates(v: string[]) {\n this[SYM_UPDATES] = v;\n }\n\n /** @internal */\n get __isNew(): boolean {\n return this[SYM_IS_NEW];\n }\n set __isNew(v: boolean) {\n this[SYM_IS_NEW] = v;\n }\n\n /** @internal */\n get __debounceMs(): number {\n return this[SYM_DEBOUNCE];\n }\n set __debounceMs(v: number) {\n this[SYM_DEBOUNCE] = v;\n }\n\n /** @internal */\n get __patchingColumns(): Set<string> {\n return this[SYM_PATCHING];\n }\n\n /** @internal */\n get __pendingKeys(): ReadonlySet<string> {\n const keys = new Set(this[SYM_UPDATES]);\n for (const col of this[SYM_PATCHING]) keys.add(col);\n return keys;\n }\n\n // ── Persistence ──────────────────────────────────────────────────────\n\n async save(immediate?: boolean): Promise<void> {\n if (immediate || this[SYM_DEBOUNCE] <= 0) {\n return this._flush();\n }\n\n if (this[SYM_SAVE_TIMER]) clearTimeout(this[SYM_SAVE_TIMER]);\n\n return new Promise<void>((resolve) => {\n this[SYM_SAVE_TIMER] = setTimeout(async () => {\n this[SYM_SAVE_TIMER] = null;\n await this._flush();\n resolve();\n }, this[SYM_DEBOUNCE]);\n });\n }\n\n private async _flush(): Promise<void> {\n const updates = [...this[SYM_UPDATES]];\n this[SYM_UPDATES] = [];\n\n if (updates.length === 0 && !this[SYM_IS_NEW]) return;\n\n const changes: ChangeSet = {\n updates,\n ops: [],\n creating: this[SYM_IS_NEW],\n };\n\n (this as any).updatedAt = new Date().toISOString();\n\n await this[SYM_ADAPTER].save(this, changes);\n this[SYM_IS_NEW] = false;\n this.emit(\"saved\", this);\n }\n\n async patch(ops: PatchOp[]): Promise<void> {\n const columns = new Set<string>();\n for (const op of ops) {\n const parts = op.path.split(\"/\").filter(Boolean);\n if (parts[0]) columns.add(parts[0]);\n }\n\n for (const col of columns) this[SYM_PATCHING].add(col);\n\n try {\n // Apply locally (optimistic) — build a data object for applyPatch\n const localData = this.__data;\n\n // Ensure intermediate objects exist for nested paths\n for (const op of ops) {\n const segments = op.path.split(\"/\").filter(Boolean);\n let cursor: any = localData;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]!;\n if (cursor[seg] == null) cursor[seg] = {};\n cursor = cursor[seg];\n }\n }\n\n applyPatch(localData, ops, false, true);\n // Write patched values back\n for (const col of columns) {\n if (col in localData) (this as any)[col] = localData[col];\n }\n\n await this[SYM_ADAPTER].patch(this, ops);\n this.emit(\"patched\", this);\n } finally {\n for (const col of columns) this[SYM_PATCHING].delete(col);\n }\n }\n\n async remove(): Promise<void> {\n await this[SYM_ADAPTER].remove(this);\n this.emit(\"removed\", this);\n }\n\n async refresh(): Promise<void> {\n const ModelClass = this.constructor as ModelConstructor;\n const fresh = await this[SYM_ADAPTER].findById(\n ModelClass,\n (this as any).id,\n );\n if (fresh) {\n const freshData = (fresh as any).__data;\n const pendingKeys = this.__pendingKeys;\n for (const key of Object.keys(freshData)) {\n if (!pendingKeys.has(key)) {\n (this as any)[key] = freshData[key];\n }\n }\n }\n }\n\n async load(): Promise<void> {\n return this.refresh();\n }\n\n async sanitize(_user?: { id: string }): Promise<Record<string, any>> {\n return { type: (this as any).type, ...this.__data };\n }\n\n toJSON(): Record<string, any> {\n return { type: (this as any).type, ...this.__data };\n }\n\n // ── Reference Proxy ──────────────────────────────────────────────────\n\n private static __refCache = new Map<string, any>();\n\n private _createRefProxy(targetClass: ModelConstructor, refId: string): any {\n const cacheKey = `${targetClass.type}:${refId}`;\n const cached = Model.__refCache.get(cacheKey);\n if (cached) return cached;\n\n let loaded: any = null;\n let loading: Promise<any> | null = null;\n\n return new Proxy({} as any, {\n get(_target, prop) {\n if (prop === \"id\") return refId;\n if (prop === \"type\") return targetClass.type;\n if (prop === \"then\") return undefined;\n if (prop === \"toJSON\")\n return () => ({ id: refId, type: targetClass.type });\n if (prop === Symbol.toPrimitive) return () => refId;\n\n if (loaded) return (loaded as any)[prop];\n\n if (!loading) {\n loading = Model.getAdapter()\n .findById(targetClass, refId)\n .then((result) => {\n loaded = result;\n Model.__refCache.set(cacheKey, loaded);\n return result;\n });\n }\n\n throw loading;\n },\n });\n }\n}\n\n// Symbol declarations for TypeScript\ndeclare module \"./Model\" {\n interface Model {\n [SYM_ADAPTER]: ModelAdapter;\n [SYM_UPDATES]: string[];\n [SYM_PATCHING]: Set<string>;\n [SYM_IS_NEW]: boolean;\n [SYM_SAVE_TIMER]: ReturnType<typeof setTimeout> | null;\n [SYM_DEBOUNCE]: number;\n [SYM_IS_PROXY]: boolean;\n [SYM_INIT_DATA]: Set<string> | undefined;\n }\n}\n\nexport default Model;\n"]} | ||
| {"version":3,"sources":["../src/Model.ts"],"names":["target"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @parcae/model — Model Base Class\n *\n * The instance IS the data store. No separate __data object.\n * A Proxy wraps the instance for change tracking and ref resolution.\n * Class property defaults (title = \"\", published = false) work naturally\n * because they set directly on the instance which the Proxy intercepts.\n *\n * Internal state uses Symbol keys to avoid collisions with data properties.\n */\n\nimport { EventEmitter } from \"eventemitter3\";\nimport ShortId from \"short-unique-id\";\nimport { applyPatch } from \"fast-json-patch\";\nimport type {\n ModelAdapter,\n ModelConstructor,\n ChangeSet,\n QueryChain,\n SchemaDefinition,\n PatchOp,\n} from \"./adapters/types\";\n\n// ─── ID Generation ───────────────────────────────────────────────────────────\n\nconst uid = new ShortId({ length: 20 });\n\nexport function generateId(): string {\n return uid.rnd();\n}\n\n// ─── Symbols for internal state (never collide with data properties) ─────────\n\nconst SYM_ADAPTER = Symbol(\"parcae:adapter\");\nconst SYM_UPDATES = Symbol(\"parcae:updates\");\nconst SYM_PATCHING = Symbol(\"parcae:patching\");\nconst SYM_IS_NEW = Symbol(\"parcae:isNew\");\nconst SYM_SAVE_TIMER = Symbol(\"parcae:saveTimer\");\nconst SYM_DEBOUNCE = Symbol(\"parcae:debounceMs\");\nconst SYM_IS_PROXY = Symbol(\"parcae:isProxy\");\nconst SYM_INIT_DATA = Symbol(\"parcae:initData\");\n\n// ─── Keys that should NOT be treated as data ─────────────────────────────────\n\nconst INSTANCE_METHODS = new Set([\n \"save\",\n \"patch\",\n \"remove\",\n \"refresh\",\n \"load\",\n \"sanitize\",\n \"toJSON\",\n \"_flush\",\n \"_createRefProxy\",\n \"constructor\",\n]);\n\n// ─── Lazy Query Chain ────────────────────────────────────────────────────────\n// Records query steps without needing an adapter. The adapter is resolved\n// lazily when a terminal method (.find(), .first(), .count()) is called.\n// This allows building queries before Model.use() is called (e.g. in React\n// component bodies before ParcaeProvider mounts).\n\nfunction lazyQuery<T>(\n modelClass: ModelConstructor<T>,\n steps: any[] = [],\n): QueryChain<T> {\n const CHAINABLE = [\n \"select\",\n \"where\",\n \"andWhere\",\n \"orWhere\",\n \"whereIn\",\n \"whereNot\",\n \"whereNotIn\",\n \"whereNull\",\n \"whereNotNull\",\n \"whereBetween\",\n \"whereRaw\",\n \"orWhereRaw\",\n \"orWhereIn\",\n \"orWhereNull\",\n \"whereExists\",\n \"orderBy\",\n \"orderByRaw\",\n \"groupBy\",\n \"groupByRaw\",\n \"having\",\n \"havingRaw\",\n \"limit\",\n \"offset\",\n \"distinct\",\n \"distinctOn\",\n \"join\",\n \"innerJoin\",\n \"leftJoin\",\n \"rightJoin\",\n \"clearOrder\",\n \"clearSelect\",\n \"from\",\n \"sum\",\n \"avg\",\n \"min\",\n \"max\",\n \"increment\",\n \"decrement\",\n ] as const;\n\n const chain: any = {};\n\n for (const method of CHAINABLE) {\n chain[method] = (...args: any[]) =>\n lazyQuery(modelClass, [...steps, { method, args }]);\n }\n\n chain.basic = (\n limit = 25,\n sort = \"createdAt\",\n direction: \"asc\" | \"desc\" = \"desc\",\n page = 0,\n ) =>\n lazyQuery(modelClass, [\n ...steps,\n { method: \"orderBy\", args: [sort, direction] },\n { method: \"limit\", args: [limit] },\n { method: \"offset\", args: [page * limit] },\n ]);\n\n // Terminal methods — resolve adapter here (async, waits if not set yet)\n const resolve = async (): Promise<QueryChain<T>> => {\n const adapter = Model.hasAdapter()\n ? Model.getAdapter()\n : await Model.waitForAdapter();\n let q = adapter.query(modelClass);\n for (const step of steps) {\n q = (q as any)[step.method](...step.args);\n }\n return q;\n };\n\n chain.find = async () => (await resolve()).find();\n chain.findAndSubscribe = async () => (await resolve()).findAndSubscribe();\n chain.first = async () => (await resolve()).first();\n chain.count = async () => (await resolve()).count();\n\n // Internal metadata\n chain.__steps = steps;\n chain.__modelType = modelClass.type;\n chain.__modelClass = modelClass;\n chain.__adapter = null; // resolved lazily\n\n return chain as QueryChain<T>;\n}\n\n// ─── Keys ────────────────────────────────────────────────────────────────────\n\nconst EVENTEMITTER_KEYS = new Set([\n \"emit\",\n \"on\",\n \"off\",\n \"once\",\n \"removeListener\",\n \"removeAllListeners\",\n \"listeners\",\n \"listenerCount\",\n \"addListener\",\n \"eventNames\",\n \"_events\",\n \"_eventsCount\",\n]);\n\n/** Properties that are part of the data but handled specially. */\nconst SYSTEM_DATA_KEYS = new Set([\"id\", \"type\", \"createdAt\", \"updatedAt\"]);\n\n// ─── Model Class ─────────────────────────────────────────────────────────────\n\nexport class Model extends EventEmitter {\n // ── Static ─────────────────────────────────────────────────────────\n\n static type: string = \"\";\n static path?: string;\n static scope?: {\n read?: (ctx: any) => any;\n create?: (ctx: any) => any;\n update?: (ctx: any) => any;\n delete?: (ctx: any) => any;\n patch?: (ctx: any) => any;\n };\n static indexes?: (string | string[])[];\n static managed: boolean = true;\n /** @internal */\n static __schema?: SchemaDefinition;\n\n // Adapter lives on globalThis so it works across multiple copies of @parcae/model\n // (pnpm can install multiple versions — they all need to share the same adapter)\n private static get __adapter(): ModelAdapter | null {\n return (globalThis as any).__parcae_adapter ?? null;\n }\n private static set __adapter(v: ModelAdapter | null) {\n (globalThis as any).__parcae_adapter = v;\n }\n private static get __pendingAdapter(): Promise<ModelAdapter> | null {\n return (globalThis as any).__parcae_pending ?? null;\n }\n private static set __pendingAdapter(v: Promise<ModelAdapter> | null) {\n (globalThis as any).__parcae_pending = v;\n }\n private static get __resolveAdapter():\n | ((adapter: ModelAdapter) => void)\n | null {\n return (globalThis as any).__parcae_resolve ?? null;\n }\n private static set __resolveAdapter(\n v: ((adapter: ModelAdapter) => void) | null,\n ) {\n (globalThis as any).__parcae_resolve = v;\n }\n\n static use(adapter: ModelAdapter): void {\n Model.__adapter = adapter;\n if (Model.__resolveAdapter) {\n Model.__resolveAdapter(adapter);\n Model.__resolveAdapter = null;\n Model.__pendingAdapter = null;\n }\n }\n\n static getAdapter(): ModelAdapter {\n if (!Model.__adapter) {\n throw new Error(\n \"No adapter set. Call Model.use(adapter) before using models.\",\n );\n }\n return Model.__adapter;\n }\n\n static hasAdapter(): boolean {\n return Model.__adapter !== null;\n }\n\n static waitForAdapter(): Promise<ModelAdapter> {\n if (Model.__adapter) return Promise.resolve(Model.__adapter);\n if (!Model.__pendingAdapter) {\n Model.__pendingAdapter = new Promise<ModelAdapter>((resolve) => {\n Model.__resolveAdapter = resolve;\n });\n }\n return Model.__pendingAdapter;\n }\n\n // ── Static Query Methods ───────────────────────────────────────────\n //\n // These build lazy query chains that only resolve the adapter at\n // execution time (.find(), .first(), .count()). This allows you to\n // build queries before the adapter is set (e.g. in React component\n // bodies before the ParcaeProvider mounts).\n\n /** Build a lazy query chain for this model class. */\n private static _query<T extends Model>(\n this: ModelConstructor<T>,\n ): QueryChain<T> {\n const ModelClass = this;\n return lazyQuery(ModelClass);\n }\n\n static create<T extends Model>(\n this: ModelConstructor<T>,\n data?: Record<string, any>,\n ): T {\n const instance = new this(Model.getAdapter(), {\n ...data,\n id: data?.id ?? generateId(),\n });\n (instance as any)[SYM_IS_NEW] = true;\n return instance;\n }\n\n static findById<T extends Model>(\n this: ModelConstructor<T>,\n id: string,\n ): Promise<T | null> {\n return Model.getAdapter().findById(this, id);\n }\n\n static where<T extends Model>(\n this: ModelConstructor<T>,\n ...args: any[]\n ): QueryChain<T> {\n return (this as any)._query().where(...args);\n }\n\n static whereRaw<T extends Model>(\n this: ModelConstructor<T>,\n query: string,\n ...bindings: any[]\n ): QueryChain<T> {\n return (this as any)._query().whereRaw(query, ...bindings);\n }\n\n static whereIn<T extends Model>(\n this: ModelConstructor<T>,\n column: string,\n values: any[],\n ): QueryChain<T> {\n return (this as any)._query().whereIn(column, values);\n }\n\n static whereNot<T extends Model>(\n this: ModelConstructor<T>,\n ...args: any[]\n ): QueryChain<T> {\n return (this as any)._query().whereNot(...args);\n }\n\n static whereNotIn<T extends Model>(\n this: ModelConstructor<T>,\n column: string,\n values: any[],\n ): QueryChain<T> {\n return (this as any)._query().whereNotIn(column, values);\n }\n\n static select<T extends Model>(\n this: ModelConstructor<T>,\n ...columns: string[]\n ): QueryChain<T> {\n return (this as any)._query().select(...columns);\n }\n\n static count<T extends Model>(this: ModelConstructor<T>): Promise<number> {\n return (this as any)._query().count();\n }\n\n static basic<T extends Model>(\n this: ModelConstructor<T>,\n limit?: number,\n sort?: string,\n direction?: \"asc\" | \"desc\",\n page?: number,\n ): QueryChain<T> {\n return (this as any)._query().basic(limit, sort, direction, page);\n }\n\n // ── Constructor ────────────────────────────────────────────────────\n\n constructor(adapter: ModelAdapter, data?: Record<string, any>) {\n super();\n\n // Set internal state via symbols (invisible to data property access)\n this[SYM_ADAPTER] = adapter;\n this[SYM_UPDATES] = [] as string[];\n this[SYM_PATCHING] = new Set<string>();\n this[SYM_IS_NEW] = false;\n this[SYM_SAVE_TIMER] = null;\n this[SYM_DEBOUNCE] = 0;\n this[SYM_IS_PROXY] = false;\n\n // Store the init data keys so the Proxy set trap knows which values\n // were explicitly provided (and shouldn't be overwritten by class\n // property defaults that run AFTER super() returns).\n const initDataKeys = new Set(data ? Object.keys(data) : []);\n this[SYM_INIT_DATA] = initDataKeys;\n\n // Set system data properties directly on the instance\n (this as any).id = data?.id ?? generateId();\n (this as any).type = (this.constructor as typeof Model).type;\n (this as any).createdAt = data?.createdAt ?? new Date().toISOString();\n (this as any).updatedAt = data?.updatedAt ?? new Date().toISOString();\n\n // Set all provided data on the instance BEFORE the Proxy wraps it.\n // These go directly on `this`, bypassing the Proxy.\n if (data) {\n for (const [key, value] of Object.entries(data)) {\n if (!SYSTEM_DATA_KEYS.has(key)) {\n (this as any)[key] = value;\n }\n }\n }\n\n // Return a Proxy for change tracking and ref resolution\n const proxy = new Proxy(this, {\n set(target, prop, value) {\n if (typeof prop === \"symbol\") {\n (target as any)[prop] = value;\n return true;\n }\n\n // EventEmitter internals — set directly, no tracking\n if (EVENTEMITTER_KEYS.has(prop)) {\n (target as any)[prop] = value;\n return true;\n }\n\n // Reference property — accept Model instance (extract ID) or raw value\n const schema = (target.constructor as typeof Model).__schema;\n if (schema && prop in schema) {\n const colDef = schema[prop];\n if (\n typeof colDef === \"object\" &&\n colDef !== null &&\n \"kind\" in colDef &&\n colDef.kind === \"ref\"\n ) {\n (target as any)[prop] =\n value instanceof Model ? (value as any).id : value;\n target[SYM_UPDATES].push(prop);\n return true;\n }\n }\n\n // $-prefixed write — raw ID for refs\n if (typeof prop === \"string\" && prop.startsWith(\"$\")) {\n const realKey = prop.slice(1);\n (target as any)[realKey] = value;\n target[SYM_UPDATES].push(realKey);\n return true;\n }\n\n // During construction (before SYM_IS_PROXY is set), class property\n // initializers fire. If this key was explicitly provided in the\n // constructor data, don't let the default overwrite it.\n if (!target[SYM_IS_PROXY] && target[SYM_INIT_DATA]?.has(prop)) {\n // Skip — the explicit value is already set on the instance\n return true;\n }\n\n // Regular data property — set on the instance, track the change\n (target as any)[prop] = value;\n\n // Only track changes for data properties (not during construction)\n if (\n target[SYM_IS_PROXY] &&\n !SYSTEM_DATA_KEYS.has(prop) &&\n !INSTANCE_METHODS.has(prop)\n ) {\n target[SYM_UPDATES].push(prop);\n }\n\n return true;\n },\n\n get(target, prop) {\n if (typeof prop === \"symbol\") {\n return (target as any)[prop];\n }\n\n // $-prefixed access — raw ID for reference properties\n if (typeof prop === \"string\" && prop.startsWith(\"$\")) {\n const realKey = prop.slice(1);\n return (target as any)[realKey];\n }\n\n // Reference property — return lazy-loading proxy\n const schema = (target.constructor as typeof Model).__schema;\n if (schema && prop in schema) {\n const colDef = schema[prop];\n if (\n typeof colDef === \"object\" &&\n colDef !== null &&\n \"kind\" in colDef &&\n colDef.kind === \"ref\"\n ) {\n const refId = (target as any)[prop];\n if (!refId) return null;\n return target._createRefProxy(colDef.target, refId);\n }\n }\n\n return (target as any)[prop];\n },\n\n has(target, prop) {\n return prop in target;\n },\n\n // Class field initializers use [[DefineOwnProperty]], not [[Set]].\n // This trap intercepts them so we can skip defaults for keys that\n // were explicitly provided in the constructor data.\n defineProperty(target, prop, descriptor) {\n if (typeof prop === \"symbol\") {\n return Reflect.defineProperty(target, prop, descriptor);\n }\n\n // During construction: if this key was in init data, skip the default\n if (\n !target[SYM_IS_PROXY] &&\n target[SYM_INIT_DATA]?.has(prop as string)\n ) {\n return true;\n }\n\n // EventEmitter internals — define directly\n if (EVENTEMITTER_KEYS.has(prop)) {\n return Reflect.defineProperty(target, prop, descriptor);\n }\n\n // Normal data property — define it (this is a class field default)\n return Reflect.defineProperty(target, prop, descriptor);\n },\n });\n\n // SYM_IS_PROXY starts false (set earlier). Property initializers from the\n // subclass run after this return, setting defaults on the proxy. The set\n // trap skips change tracking when SYM_IS_PROXY is false. After construction\n // completes, the first explicit write flips it to true via a lazy check.\n //\n // But we need a way to flip it. Use a microtask: by the time any user code\n // runs (which is async or at least after the constructor call), the\n // microtask will have fired.\n const target = this;\n queueMicrotask(() => {\n target[SYM_IS_PROXY] = true;\n delete (target as any)[SYM_INIT_DATA];\n });\n\n return proxy;\n }\n\n // ── Data Access (for adapters/serialization) ──────────────────────\n\n /**\n * Get all data properties as a plain object.\n * Used by adapters for serialization. Excludes methods, symbols, and EE internals.\n */\n get __data(): Record<string, any> {\n const data: Record<string, any> = {};\n for (const key of Object.keys(this)) {\n if (EVENTEMITTER_KEYS.has(key)) continue;\n if (INSTANCE_METHODS.has(key)) continue;\n if (key.startsWith(\"_\")) continue;\n data[key] = (this as any)[key];\n }\n return data;\n }\n\n /**\n * Set data properties from a plain object (used by adapters during hydration).\n */\n set __data(data: Record<string, any>) {\n for (const [key, value] of Object.entries(data)) {\n (this as any)[key] = value;\n }\n }\n\n /** @internal */\n get __updates(): string[] {\n return this[SYM_UPDATES];\n }\n set __updates(v: string[]) {\n this[SYM_UPDATES] = v;\n }\n\n /** @internal */\n get __isNew(): boolean {\n return this[SYM_IS_NEW];\n }\n set __isNew(v: boolean) {\n this[SYM_IS_NEW] = v;\n }\n\n /** @internal */\n get __debounceMs(): number {\n return this[SYM_DEBOUNCE];\n }\n set __debounceMs(v: number) {\n this[SYM_DEBOUNCE] = v;\n }\n\n /** @internal */\n get __patchingColumns(): Set<string> {\n return this[SYM_PATCHING];\n }\n\n /** @internal */\n get __pendingKeys(): ReadonlySet<string> {\n const keys = new Set(this[SYM_UPDATES]);\n for (const col of this[SYM_PATCHING]) keys.add(col);\n return keys;\n }\n\n // ── Persistence ──────────────────────────────────────────────────────\n\n async save(immediate?: boolean): Promise<void> {\n if (immediate || this[SYM_DEBOUNCE] <= 0) {\n return this._flush();\n }\n\n if (this[SYM_SAVE_TIMER]) clearTimeout(this[SYM_SAVE_TIMER]);\n\n return new Promise<void>((resolve) => {\n this[SYM_SAVE_TIMER] = setTimeout(async () => {\n this[SYM_SAVE_TIMER] = null;\n await this._flush();\n resolve();\n }, this[SYM_DEBOUNCE]);\n });\n }\n\n private async _flush(): Promise<void> {\n const updates = [...this[SYM_UPDATES]];\n this[SYM_UPDATES] = [];\n\n if (updates.length === 0 && !this[SYM_IS_NEW]) return;\n\n const changes: ChangeSet = {\n updates,\n ops: [],\n creating: this[SYM_IS_NEW],\n };\n\n (this as any).updatedAt = new Date().toISOString();\n\n await this[SYM_ADAPTER].save(this, changes);\n this[SYM_IS_NEW] = false;\n this.emit(\"saved\", this);\n }\n\n async patch(ops: PatchOp[]): Promise<void> {\n const columns = new Set<string>();\n for (const op of ops) {\n const parts = op.path.split(\"/\").filter(Boolean);\n if (parts[0]) columns.add(parts[0]);\n }\n\n for (const col of columns) this[SYM_PATCHING].add(col);\n\n try {\n // Apply locally (optimistic) — build a data object for applyPatch\n const localData = this.__data;\n\n // Ensure intermediate objects exist for nested paths\n for (const op of ops) {\n const segments = op.path.split(\"/\").filter(Boolean);\n let cursor: any = localData;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]!;\n if (cursor[seg] == null) cursor[seg] = {};\n cursor = cursor[seg];\n }\n }\n\n applyPatch(localData, ops, false, true);\n // Write patched values back\n for (const col of columns) {\n if (col in localData) (this as any)[col] = localData[col];\n }\n\n await this[SYM_ADAPTER].patch(this, ops);\n this.emit(\"patched\", this);\n } finally {\n for (const col of columns) this[SYM_PATCHING].delete(col);\n }\n }\n\n async remove(): Promise<void> {\n await this[SYM_ADAPTER].remove(this);\n this.emit(\"removed\", this);\n }\n\n async refresh(): Promise<void> {\n const ModelClass = this.constructor as ModelConstructor;\n const fresh = await this[SYM_ADAPTER].findById(\n ModelClass,\n (this as any).id,\n );\n if (fresh) {\n const freshData = (fresh as any).__data;\n const pendingKeys = this.__pendingKeys;\n for (const key of Object.keys(freshData)) {\n if (!pendingKeys.has(key)) {\n (this as any)[key] = freshData[key];\n }\n }\n }\n }\n\n async load(): Promise<void> {\n return this.refresh();\n }\n\n async sanitize(_user?: { id: string }): Promise<Record<string, any>> {\n return { type: (this as any).type, ...this.__data };\n }\n\n toJSON(): Record<string, any> {\n return { type: (this as any).type, ...this.__data };\n }\n\n // ── Reference Proxy ──────────────────────────────────────────────────\n\n private static __refCache = new Map<string, any>();\n\n private _createRefProxy(targetClass: ModelConstructor, refId: string): any {\n const cacheKey = `${targetClass.type}:${refId}`;\n const cached = Model.__refCache.get(cacheKey);\n if (cached) return cached;\n\n let loaded: any = null;\n let loading: Promise<any> | null = null;\n\n return new Proxy({} as any, {\n get(_target, prop) {\n if (prop === \"id\") return refId;\n if (prop === \"type\") return targetClass.type;\n if (prop === \"then\") return undefined;\n if (prop === \"toJSON\")\n return () => ({ id: refId, type: targetClass.type });\n if (prop === Symbol.toPrimitive) return () => refId;\n\n if (loaded) return (loaded as any)[prop];\n\n if (!loading) {\n loading = Model.getAdapter()\n .findById(targetClass, refId)\n .then((result) => {\n loaded = result;\n Model.__refCache.set(cacheKey, loaded);\n return result;\n });\n }\n\n throw loading;\n },\n });\n }\n}\n\n// Symbol declarations for TypeScript\ndeclare module \"./Model\" {\n interface Model {\n [SYM_ADAPTER]: ModelAdapter;\n [SYM_UPDATES]: string[];\n [SYM_PATCHING]: Set<string>;\n [SYM_IS_NEW]: boolean;\n [SYM_SAVE_TIMER]: ReturnType<typeof setTimeout> | null;\n [SYM_DEBOUNCE]: number;\n [SYM_IS_PROXY]: boolean;\n [SYM_INIT_DATA]: Set<string> | undefined;\n }\n}\n\nexport default Model;\n"]} |
+11
-11
| { | ||
| "name": "@parcae/model", | ||
| "version": "0.6.1", | ||
| "version": "0.7.0", | ||
| "description": "Parcae Model — typed ORM base class with adapter pattern", | ||
@@ -29,10 +29,2 @@ "type": "module", | ||
| ], | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "typecheck": "tsc --noEmit", | ||
| "clean": "rm -rf dist", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest" | ||
| }, | ||
| "dependencies": { | ||
@@ -50,3 +42,11 @@ "eventemitter3": "^5.0.1", | ||
| }, | ||
| "license": "MIT" | ||
| } | ||
| "license": "MIT", | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "typecheck": "tsc --noEmit", | ||
| "clean": "rm -rf dist", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest" | ||
| } | ||
| } |
| import { proxy } from 'valtio'; | ||
| // src/adapters/client.ts | ||
| function stripVersion(path) { | ||
| return path.replace(/^\/v\d+/, ""); | ||
| } | ||
| var FrontendAdapter = class { | ||
| transport; | ||
| constructor(transport) { | ||
| this.transport = transport; | ||
| } | ||
| p(modelPath) { | ||
| return stripVersion(modelPath); | ||
| } | ||
| // ── createStore ────────────────────────────────────────────────────── | ||
| createStore(data) { | ||
| return proxy(data); | ||
| } | ||
| // ── save ───────────────────────────────────────────────────────────── | ||
| async save(model, changes) { | ||
| const ModelClass = model.constructor; | ||
| const path = this.resolvePath(ModelClass); | ||
| if (changes.creating) { | ||
| const result = await this.transport.post(path, model.__data); | ||
| if (result?.id) model.__data.id = result.id; | ||
| } else if (changes.ops.length > 0) { | ||
| await this.transport.patch(`${path}/${model.id}`, { ops: changes.ops }); | ||
| } else if (changes.updates.length > 0) { | ||
| const data = {}; | ||
| for (const key of changes.updates) { | ||
| data[key] = model.__data[key]; | ||
| } | ||
| await this.transport.put(`${path}/${model.id}`, data); | ||
| } | ||
| } | ||
| // ── remove ─────────────────────────────────────────────────────────── | ||
| async remove(model) { | ||
| const ModelClass = model.constructor; | ||
| const path = this.resolvePath(ModelClass); | ||
| await this.transport.delete(`${path}/${model.id}`); | ||
| } | ||
| // ── findById ───────────────────────────────────────────────────────── | ||
| async findById(modelClass, id) { | ||
| const path = this.resolvePath(modelClass); | ||
| try { | ||
| const data = await this.transport.get(`${path}/${id}`); | ||
| if (!data) return null; | ||
| return new modelClass(this, data); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| // ── query ──────────────────────────────────────────────────────────── | ||
| query(modelClass) { | ||
| return this._buildQuery(modelClass, []); | ||
| } | ||
| _buildQuery(modelClass, steps) { | ||
| const adapter = this; | ||
| const CHAINABLE = [ | ||
| "select", | ||
| "where", | ||
| "andWhere", | ||
| "orWhere", | ||
| "whereIn", | ||
| "whereNot", | ||
| "whereNotIn", | ||
| "whereNull", | ||
| "whereNotNull", | ||
| "whereBetween", | ||
| "whereRaw", | ||
| "orWhereRaw", | ||
| "orWhereIn", | ||
| "orWhereNull", | ||
| "whereExists", | ||
| "orderBy", | ||
| "orderByRaw", | ||
| "groupBy", | ||
| "groupByRaw", | ||
| "having", | ||
| "havingRaw", | ||
| "limit", | ||
| "offset", | ||
| "distinct", | ||
| "distinctOn", | ||
| "join", | ||
| "innerJoin", | ||
| "leftJoin", | ||
| "rightJoin", | ||
| "clearOrder", | ||
| "clearSelect", | ||
| "from", | ||
| "sum", | ||
| "avg", | ||
| "min", | ||
| "max", | ||
| "increment", | ||
| "decrement" | ||
| ]; | ||
| const chain = {}; | ||
| for (const method of CHAINABLE) { | ||
| chain[method] = (...args) => { | ||
| return adapter._buildQuery(modelClass, [ | ||
| ...steps, | ||
| { method, args: adapter._serializeArgs(args) } | ||
| ]); | ||
| }; | ||
| } | ||
| chain.basic = (limit = 25, sort = "createdAt", direction = "desc", page = 0) => { | ||
| return adapter._buildQuery(modelClass, [ | ||
| ...steps, | ||
| { method: "orderBy", args: [sort, direction] }, | ||
| { method: "limit", args: [limit] }, | ||
| { method: "offset", args: [page * limit] } | ||
| ]); | ||
| }; | ||
| let debounceMs = void 0; | ||
| chain.debounce = (ms) => { | ||
| debounceMs = ms; | ||
| const newChain = adapter._buildQuery(modelClass, steps); | ||
| newChain.__debounceMs = ms; | ||
| return newChain; | ||
| }; | ||
| chain.find = async () => { | ||
| const path = adapter.resolvePath(modelClass); | ||
| console.log( | ||
| "[parcae/model] find:", | ||
| path, | ||
| "transport:", | ||
| typeof adapter.transport?.get | ||
| ); | ||
| const result = await adapter.transport.get(path, { __query: steps }); | ||
| const items = result?.[modelClass.type + "s"] ?? result?.items ?? []; | ||
| return items.map((row) => new modelClass(adapter, row)); | ||
| }; | ||
| chain.first = async () => { | ||
| const all = await chain.find(); | ||
| return all[0] ?? null; | ||
| }; | ||
| chain.count = async () => { | ||
| const path = adapter.resolvePath(modelClass); | ||
| const result = await adapter.transport.get(path, { | ||
| __query: steps, | ||
| __count: true | ||
| }); | ||
| return result?.total ?? 0; | ||
| }; | ||
| chain.__steps = steps; | ||
| chain.__modelType = modelClass.type; | ||
| chain.__modelClass = modelClass; | ||
| chain.__adapter = adapter; | ||
| Object.defineProperty(chain, "__debounceMs", { | ||
| get: () => debounceMs, | ||
| enumerable: true | ||
| }); | ||
| return chain; | ||
| } | ||
| _serializeArgs(args) { | ||
| return args.map((arg) => { | ||
| if (typeof arg === "function") return "__fn__"; | ||
| return arg; | ||
| }); | ||
| } | ||
| // ── patch ──────────────────────────────────────────────────────────── | ||
| async patch(model, ops) { | ||
| const ModelClass = model.constructor; | ||
| const path = this.resolvePath(ModelClass); | ||
| await this.transport.patch(`${path}/${model.id}`, { ops }); | ||
| } | ||
| // ── helpers ────────────────────────────────────────────────────────── | ||
| resolvePath(modelClass) { | ||
| if (!modelClass.path && !modelClass.type) { | ||
| throw new Error(`Model has no path or type`); | ||
| } | ||
| const fullPath = modelClass.path ?? `/v1/${modelClass.type}s`; | ||
| return this.p(fullPath); | ||
| } | ||
| }; | ||
| var client_default = FrontendAdapter; | ||
| export { FrontendAdapter, client_default }; | ||
| //# sourceMappingURL=chunk-CHRGDH3V.js.map | ||
| //# sourceMappingURL=chunk-CHRGDH3V.js.map |
| {"version":3,"sources":["../src/adapters/client.ts"],"names":[],"mappings":"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","file":"chunk-CHRGDH3V.js","sourcesContent":["/**\n * FrontendAdapter — Valtio + Transport for Parcae Model.\n *\n * Transport-agnostic. Works with any implementation of the Transport interface:\n * - SocketTransport (Socket.IO — bidirectional, realtime)\n * - SSETransport (Server-Sent Events — read-heavy, simpler)\n * - GRPCTransport (gRPC — service-to-service)\n * - Or any custom transport\n */\n\nimport { proxy } from \"valtio\";\nimport type {\n ModelAdapter,\n ModelConstructor,\n ChangeSet,\n QueryChain,\n QueryStep,\n PatchOp,\n} from \"./types\";\n\n// ─── Transport Interface ─────────────────────────────────────────────────────\n\n/**\n * Abstract transport layer. Decouples the Model system from the wire protocol.\n *\n * Implementations:\n * - SocketTransport: Socket.IO (bidirectional, realtime subscriptions)\n * - SSETransport: HTTP + Server-Sent Events (read-heavy, simpler infra)\n * - GRPCTransport: gRPC (service-to-service, protobuf)\n */\nexport interface Transport {\n // ── Request/Response (RPC-style) ────────────────────────────────────\n get(path: string, data?: any): Promise<any>;\n post(path: string, data?: any): Promise<any>;\n put(path: string, data?: any): Promise<any>;\n patch(path: string, data?: any): Promise<any>;\n delete(path: string, data?: any): Promise<any>;\n\n // ── Subscriptions (realtime) ────────────────────────────────────────\n /**\n * Subscribe to a named event stream.\n * Returns a dispose function to unsubscribe.\n *\n * Socket.IO: socket.on(event, handler)\n * SSE: new EventSource(url) per channel\n * gRPC: server streaming RPC\n */\n subscribe?(event: string, handler: (...args: any[]) => void): () => void;\n\n /**\n * Unsubscribe from a named event stream.\n * Alternative to calling the dispose function returned by subscribe().\n */\n unsubscribe?(event: string, handler?: (...args: any[]) => void): void;\n\n // ── Control messages ────────────────────────────────────────────────\n /**\n * Send a control message to the server (fire-and-forget).\n *\n * Socket.IO: socket.emit(event, ...args)\n * SSE: POST /v1/__control { event, args }\n * gRPC: unary RPC\n */\n send?(event: string, ...args: any[]): void;\n\n // ── Connection state ────────────────────────────────────────────────\n /** Whether the transport is currently connected. */\n readonly isConnected?: boolean;\n /** Whether the transport is currently loading/connecting. */\n readonly isLoading?: boolean;\n\n /**\n * Listen for connection state changes.\n * Events: \"connected\", \"disconnected\", \"reconnecting\", \"error\"\n */\n on?(event: string, handler: (...args: any[]) => void): void;\n off?(event: string, handler?: (...args: any[]) => void): void;\n\n /** Disconnect the transport. */\n disconnect?(): void;\n /** Reconnect the transport. */\n reconnect?(): Promise<void>;\n}\n\n/**\n * Strip version prefix from a path if it starts with /v{number}.\n * The transport prepends the version automatically.\n */\nfunction stripVersion(path: string): string {\n return path.replace(/^\\/v\\d+/, \"\");\n}\n\n// ─── FrontendAdapter ─────────────────────────────────────────────────────────\n\nexport class FrontendAdapter implements ModelAdapter {\n public transport: Transport;\n\n constructor(transport: Transport) {\n this.transport = transport;\n }\n\n private p(modelPath: string): string {\n return stripVersion(modelPath);\n }\n\n // ── createStore ──────────────────────────────────────────────────────\n\n createStore(data: Record<string, any>): Record<string, any> {\n return proxy(data);\n }\n\n // ── save ─────────────────────────────────────────────────────────────\n\n async save(model: any, changes: ChangeSet): Promise<void> {\n const ModelClass = model.constructor as ModelConstructor;\n const path = this.resolvePath(ModelClass);\n\n if (changes.creating) {\n const result = await this.transport.post(path, model.__data);\n if (result?.id) model.__data.id = result.id;\n } else if (changes.ops.length > 0) {\n await this.transport.patch(`${path}/${model.id}`, { ops: changes.ops });\n } else if (changes.updates.length > 0) {\n const data: Record<string, any> = {};\n for (const key of changes.updates) {\n data[key] = model.__data[key];\n }\n await this.transport.put(`${path}/${model.id}`, data);\n }\n }\n\n // ── remove ───────────────────────────────────────────────────────────\n\n async remove(model: any): Promise<void> {\n const ModelClass = model.constructor as ModelConstructor;\n const path = this.resolvePath(ModelClass);\n await this.transport.delete(`${path}/${model.id}`);\n }\n\n // ── findById ─────────────────────────────────────────────────────────\n\n async findById<T>(\n modelClass: ModelConstructor<T>,\n id: string,\n ): Promise<T | null> {\n const path = this.resolvePath(modelClass);\n try {\n const data = await this.transport.get(`${path}/${id}`);\n if (!data) return null;\n return new modelClass(this, data) as T;\n } catch {\n return null;\n }\n }\n\n // ── query ────────────────────────────────────────────────────────────\n\n query<T>(modelClass: ModelConstructor<T>): QueryChain<T> {\n return this._buildQuery(modelClass, []);\n }\n\n private _buildQuery<T>(\n modelClass: ModelConstructor<T>,\n steps: QueryStep[],\n ): QueryChain<T> {\n const adapter = this;\n\n const CHAINABLE = [\n \"select\",\n \"where\",\n \"andWhere\",\n \"orWhere\",\n \"whereIn\",\n \"whereNot\",\n \"whereNotIn\",\n \"whereNull\",\n \"whereNotNull\",\n \"whereBetween\",\n \"whereRaw\",\n \"orWhereRaw\",\n \"orWhereIn\",\n \"orWhereNull\",\n \"whereExists\",\n \"orderBy\",\n \"orderByRaw\",\n \"groupBy\",\n \"groupByRaw\",\n \"having\",\n \"havingRaw\",\n \"limit\",\n \"offset\",\n \"distinct\",\n \"distinctOn\",\n \"join\",\n \"innerJoin\",\n \"leftJoin\",\n \"rightJoin\",\n \"clearOrder\",\n \"clearSelect\",\n \"from\",\n \"sum\",\n \"avg\",\n \"min\",\n \"max\",\n \"increment\",\n \"decrement\",\n ] as const;\n\n const chain: any = {};\n\n for (const method of CHAINABLE) {\n chain[method] = (...args: any[]) => {\n return adapter._buildQuery(modelClass, [\n ...steps,\n { method, args: adapter._serializeArgs(args) },\n ]);\n };\n }\n\n chain.basic = (\n limit: number = 25,\n sort: string = \"createdAt\",\n direction: \"asc\" | \"desc\" = \"desc\",\n page: number = 0,\n ) => {\n return adapter._buildQuery(modelClass, [\n ...steps,\n { method: \"orderBy\", args: [sort, direction] },\n { method: \"limit\", args: [limit] },\n { method: \"offset\", args: [page * limit] },\n ]);\n };\n\n let debounceMs: number | undefined = undefined;\n chain.debounce = (ms: number) => {\n debounceMs = ms;\n const newChain = adapter._buildQuery(modelClass, steps);\n (newChain as any).__debounceMs = ms;\n return newChain;\n };\n\n chain.find = async (): Promise<T[]> => {\n const path = adapter.resolvePath(modelClass);\n console.log(\n \"[parcae/model] find:\",\n path,\n \"transport:\",\n typeof adapter.transport?.get,\n );\n const result = await adapter.transport.get(path, { __query: steps });\n const items = result?.[modelClass.type + \"s\"] ?? result?.items ?? [];\n return items.map((row: any) => new modelClass(adapter, row));\n };\n\n chain.first = async (): Promise<T | null> => {\n const all = await chain.find();\n return all[0] ?? null;\n };\n\n chain.count = async (): Promise<number> => {\n const path = adapter.resolvePath(modelClass);\n const result = await adapter.transport.get(path, {\n __query: steps,\n __count: true,\n });\n return result?.total ?? 0;\n };\n\n chain.__steps = steps;\n chain.__modelType = modelClass.type;\n chain.__modelClass = modelClass;\n chain.__adapter = adapter;\n Object.defineProperty(chain, \"__debounceMs\", {\n get: () => debounceMs,\n enumerable: true,\n });\n\n return chain as QueryChain<T>;\n }\n\n private _serializeArgs(args: any[]): any[] {\n return args.map((arg) => {\n if (typeof arg === \"function\") return \"__fn__\";\n return arg;\n });\n }\n\n // ── patch ────────────────────────────────────────────────────────────\n\n async patch(model: any, ops: PatchOp[]): Promise<void> {\n const ModelClass = model.constructor as ModelConstructor;\n const path = this.resolvePath(ModelClass);\n await this.transport.patch(`${path}/${model.id}`, { ops });\n }\n\n // ── helpers ──────────────────────────────────────────────────────────\n\n private resolvePath(modelClass: ModelConstructor): string {\n if (!modelClass.path && !modelClass.type) {\n throw new Error(`Model has no path or type`);\n }\n const fullPath = modelClass.path ?? `/v1/${modelClass.type}s`;\n return this.p(fullPath);\n }\n}\n\nexport default FrontendAdapter;\n"]} |
101051
1.24%1037
0.78%