@objectstack/client 4.0.1 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +16 -0
- package/dist/index.d.mts +95 -9
- package/dist/index.d.ts +95 -9
- package/dist/index.js +159 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +158 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -12
- package/src/client.test.ts +4 -12
- package/src/index.ts +43 -23
- package/src/realtime-api.ts +208 -0
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,135 @@
|
|
|
2
2
|
import { isFilterAST } from "@objectstack/spec/data";
|
|
3
3
|
import { createLogger } from "@objectstack/core";
|
|
4
4
|
|
|
5
|
+
// src/realtime-api.ts
|
|
6
|
+
var RealtimeAPI = class {
|
|
7
|
+
constructor(baseUrl, token) {
|
|
8
|
+
this.subscriptions = /* @__PURE__ */ new Map();
|
|
9
|
+
this.eventBuffer = [];
|
|
10
|
+
this._baseUrl = baseUrl;
|
|
11
|
+
this._token = token;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Subscribe to metadata events
|
|
15
|
+
* Returns an unsubscribe function
|
|
16
|
+
*/
|
|
17
|
+
subscribeMetadata(type, callback, options) {
|
|
18
|
+
const subscriptionId = `metadata-${type}-${Date.now()}`;
|
|
19
|
+
this.subscriptions.set(subscriptionId, {
|
|
20
|
+
filter: {
|
|
21
|
+
type,
|
|
22
|
+
packageId: options?.packageId,
|
|
23
|
+
eventTypes: [
|
|
24
|
+
`metadata.${type}.created`,
|
|
25
|
+
`metadata.${type}.updated`,
|
|
26
|
+
`metadata.${type}.deleted`
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
handler: (event) => {
|
|
30
|
+
if (event.type.startsWith("metadata.")) {
|
|
31
|
+
callback(event);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
this.startPolling();
|
|
36
|
+
return () => {
|
|
37
|
+
this.subscriptions.delete(subscriptionId);
|
|
38
|
+
if (this.subscriptions.size === 0) {
|
|
39
|
+
this.stopPolling();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Subscribe to data record events
|
|
45
|
+
* Returns an unsubscribe function
|
|
46
|
+
*/
|
|
47
|
+
subscribeData(object, callback, options) {
|
|
48
|
+
const subscriptionId = `data-${object}-${Date.now()}`;
|
|
49
|
+
this.subscriptions.set(subscriptionId, {
|
|
50
|
+
filter: {
|
|
51
|
+
type: object,
|
|
52
|
+
recordId: options?.recordId,
|
|
53
|
+
eventTypes: [
|
|
54
|
+
"data.record.created",
|
|
55
|
+
"data.record.updated",
|
|
56
|
+
"data.record.deleted"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
handler: (event) => {
|
|
60
|
+
if (event.type.startsWith("data.") && event.object === object) {
|
|
61
|
+
if (!options?.recordId || event.payload?.recordId === options.recordId) {
|
|
62
|
+
callback(event);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
this.startPolling();
|
|
68
|
+
return () => {
|
|
69
|
+
this.subscriptions.delete(subscriptionId);
|
|
70
|
+
if (this.subscriptions.size === 0) {
|
|
71
|
+
this.stopPolling();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Emit an event to all matching subscriptions (client-side only)
|
|
77
|
+
* This is used for in-process event delivery
|
|
78
|
+
*/
|
|
79
|
+
emitEvent(event) {
|
|
80
|
+
for (const sub of this.subscriptions.values()) {
|
|
81
|
+
const matchesType = !sub.filter.type || event.type.includes(sub.filter.type) || event.object === sub.filter.type;
|
|
82
|
+
const matchesEventType = !sub.filter.eventTypes?.length || sub.filter.eventTypes.includes(event.type);
|
|
83
|
+
const matchesPackage = !sub.filter.packageId || event.payload?.packageId === sub.filter.packageId;
|
|
84
|
+
if (matchesType && matchesEventType && matchesPackage) {
|
|
85
|
+
try {
|
|
86
|
+
sub.handler(event);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error("Error in realtime event handler:", error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Start polling for events (fallback mechanism)
|
|
95
|
+
* In production, this would be replaced with WebSocket/SSE
|
|
96
|
+
*/
|
|
97
|
+
startPolling() {
|
|
98
|
+
if (this.pollInterval) return;
|
|
99
|
+
this.pollInterval = setInterval(() => {
|
|
100
|
+
while (this.eventBuffer.length > 0) {
|
|
101
|
+
const event = this.eventBuffer.shift();
|
|
102
|
+
if (event) {
|
|
103
|
+
this.emitEvent(event);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}, 2e3);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Stop polling for events
|
|
110
|
+
*/
|
|
111
|
+
stopPolling() {
|
|
112
|
+
if (this.pollInterval) {
|
|
113
|
+
clearInterval(this.pollInterval);
|
|
114
|
+
this.pollInterval = void 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Internal method to buffer events from server
|
|
119
|
+
* This would be called by WebSocket/SSE handlers in production
|
|
120
|
+
*/
|
|
121
|
+
_bufferEvent(event) {
|
|
122
|
+
this.eventBuffer.push(event);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Disconnect and clean up all subscriptions
|
|
126
|
+
*/
|
|
127
|
+
disconnect() {
|
|
128
|
+
this.stopPolling();
|
|
129
|
+
this.subscriptions.clear();
|
|
130
|
+
this.eventBuffer = [];
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
5
134
|
// src/query-builder.ts
|
|
6
135
|
var FilterBuilder = class {
|
|
7
136
|
constructor() {
|
|
@@ -310,10 +439,15 @@ var ObjectStackClient = class {
|
|
|
310
439
|
* Get a specific metadata item by type and name
|
|
311
440
|
* @param type - Metadata type (e.g., 'object', 'plugin')
|
|
312
441
|
* @param name - Item name (snake_case identifier)
|
|
442
|
+
* @param options - Optional filters (e.g., packageId to scope by package)
|
|
313
443
|
*/
|
|
314
|
-
getItem: async (type, name) => {
|
|
444
|
+
getItem: async (type, name, options) => {
|
|
315
445
|
const route = this.getRoute("metadata");
|
|
316
|
-
const
|
|
446
|
+
const params = new URLSearchParams();
|
|
447
|
+
if (options?.packageId) params.set("package", options.packageId);
|
|
448
|
+
const qs = params.toString();
|
|
449
|
+
const url = `${this.baseUrl}${route}/${type}/${name}${qs ? `?${qs}` : ""}`;
|
|
450
|
+
const res = await this.fetch(url);
|
|
317
451
|
return this.unwrapResponse(res);
|
|
318
452
|
},
|
|
319
453
|
/**
|
|
@@ -330,6 +464,18 @@ var ObjectStackClient = class {
|
|
|
330
464
|
});
|
|
331
465
|
return this.unwrapResponse(res);
|
|
332
466
|
},
|
|
467
|
+
/**
|
|
468
|
+
* Delete a metadata item
|
|
469
|
+
* @param type - Metadata type (e.g., 'object', 'plugin')
|
|
470
|
+
* @param name - Item name (snake_case identifier)
|
|
471
|
+
*/
|
|
472
|
+
deleteItem: async (type, name) => {
|
|
473
|
+
const route = this.getRoute("metadata");
|
|
474
|
+
const res = await this.fetch(`${this.baseUrl}${route}/${encodeURIComponent(type)}/${encodeURIComponent(name)}`, {
|
|
475
|
+
method: "DELETE"
|
|
476
|
+
});
|
|
477
|
+
return this.unwrapResponse(res);
|
|
478
|
+
},
|
|
333
479
|
/**
|
|
334
480
|
* Get object metadata with cache support
|
|
335
481
|
* Supports ETag-based conditional requests for efficient caching
|
|
@@ -1073,17 +1219,7 @@ var ObjectStackClient = class {
|
|
|
1073
1219
|
});
|
|
1074
1220
|
return this.unwrapResponse(res);
|
|
1075
1221
|
},
|
|
1076
|
-
|
|
1077
|
-
* Multi-turn AI chat
|
|
1078
|
-
*/
|
|
1079
|
-
chat: async (request) => {
|
|
1080
|
-
const route = this.getRoute("ai");
|
|
1081
|
-
const res = await this.fetch(`${this.baseUrl}${route}/chat`, {
|
|
1082
|
-
method: "POST",
|
|
1083
|
-
body: JSON.stringify(request)
|
|
1084
|
-
});
|
|
1085
|
-
return this.unwrapResponse(res);
|
|
1086
|
-
},
|
|
1222
|
+
// AI chat method removed — use Vercel AI SDK `useChat()` / `@ai-sdk/react` directly.
|
|
1087
1223
|
/**
|
|
1088
1224
|
* AI-powered field value suggestions
|
|
1089
1225
|
*/
|
|
@@ -1465,6 +1601,7 @@ var ObjectStackClient = class {
|
|
|
1465
1601
|
level: config.debug ? "debug" : "info",
|
|
1466
1602
|
format: "pretty"
|
|
1467
1603
|
});
|
|
1604
|
+
this.realtimeAPI = new RealtimeAPI(this.baseUrl, this.token);
|
|
1468
1605
|
this.logger.debug("ObjectStack client created", { baseUrl: this.baseUrl });
|
|
1469
1606
|
}
|
|
1470
1607
|
/**
|
|
@@ -1535,6 +1672,13 @@ var ObjectStackClient = class {
|
|
|
1535
1672
|
}
|
|
1536
1673
|
return result;
|
|
1537
1674
|
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Event Subscription API
|
|
1677
|
+
* Provides real-time event subscriptions for metadata and data changes
|
|
1678
|
+
*/
|
|
1679
|
+
get events() {
|
|
1680
|
+
return this.realtimeAPI;
|
|
1681
|
+
}
|
|
1538
1682
|
/**
|
|
1539
1683
|
* Private Helpers
|
|
1540
1684
|
*/
|
|
@@ -1638,6 +1782,7 @@ export {
|
|
|
1638
1782
|
FilterBuilder,
|
|
1639
1783
|
ObjectStackClient,
|
|
1640
1784
|
QueryBuilder,
|
|
1785
|
+
RealtimeAPI,
|
|
1641
1786
|
createFilter,
|
|
1642
1787
|
createQuery
|
|
1643
1788
|
};
|