@objectstack/metadata 4.1.0 → 4.2.0
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/dist/index.cjs +194 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +195 -0
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +194 -0
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +195 -0
- package/dist/node.js.map +1 -1
- package/package.json +5 -5
package/dist/node.cjs
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,6 +30,155 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/routes/hmr-routes.ts
|
|
34
|
+
var hmr_routes_exports = {};
|
|
35
|
+
__export(hmr_routes_exports, {
|
|
36
|
+
registerMetadataHmrRoutes: () => registerMetadataHmrRoutes
|
|
37
|
+
});
|
|
38
|
+
function registerMetadataHmrRoutes(app, manager, options = {}) {
|
|
39
|
+
const routePath = options.path ?? "/api/v1/dev/metadata-events";
|
|
40
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
41
|
+
const broadcast = (evt) => {
|
|
42
|
+
for (const l of listeners) {
|
|
43
|
+
try {
|
|
44
|
+
l(evt);
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
let fsHookInstalled = false;
|
|
50
|
+
const installFsHooks = async () => {
|
|
51
|
+
if (fsHookInstalled) return;
|
|
52
|
+
const mgr = manager;
|
|
53
|
+
if (typeof mgr.subscribe !== "function") {
|
|
54
|
+
fsHookInstalled = true;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const types = await manager.getRegisteredTypes();
|
|
58
|
+
for (const type of types) {
|
|
59
|
+
mgr.subscribe(type, (evt) => {
|
|
60
|
+
const ts = typeof evt.timestamp === "string" ? Date.parse(evt.timestamp) : evt.timestamp ?? Date.now();
|
|
61
|
+
broadcast({
|
|
62
|
+
kind: "metadata-change",
|
|
63
|
+
type: evt.type ?? "changed",
|
|
64
|
+
metadataType: evt.metadataType ?? type,
|
|
65
|
+
name: evt.name ?? "",
|
|
66
|
+
path: evt.path,
|
|
67
|
+
timestamp: Number.isFinite(ts) ? ts : Date.now()
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
fsHookInstalled = true;
|
|
72
|
+
};
|
|
73
|
+
installFsHooks().catch(() => {
|
|
74
|
+
});
|
|
75
|
+
let onPostReload = null;
|
|
76
|
+
app.get(routePath, async (c) => {
|
|
77
|
+
await installFsHooks().catch(() => {
|
|
78
|
+
});
|
|
79
|
+
const types = await manager.getRegisteredTypes().catch(() => []);
|
|
80
|
+
const stream = new ReadableStream({
|
|
81
|
+
async start(controller) {
|
|
82
|
+
const enc = new TextEncoder();
|
|
83
|
+
let closed = false;
|
|
84
|
+
const safeEnqueue = (chunk) => {
|
|
85
|
+
if (closed) return;
|
|
86
|
+
try {
|
|
87
|
+
controller.enqueue(enc.encode(chunk));
|
|
88
|
+
} catch {
|
|
89
|
+
closed = true;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const listener = (evt) => {
|
|
93
|
+
if (closed) return;
|
|
94
|
+
const eventName = evt.kind === "reload" ? "reload" : "metadata-change";
|
|
95
|
+
safeEnqueue(`event: ${eventName}
|
|
96
|
+
data: ${JSON.stringify(evt)}
|
|
97
|
+
|
|
98
|
+
`);
|
|
99
|
+
};
|
|
100
|
+
listeners.add(listener);
|
|
101
|
+
safeEnqueue(`event: ready
|
|
102
|
+
data: ${JSON.stringify({ types, timestamp: Date.now() })}
|
|
103
|
+
|
|
104
|
+
`);
|
|
105
|
+
const heartbeat = setInterval(() => {
|
|
106
|
+
safeEnqueue(`: ping ${Date.now()}
|
|
107
|
+
|
|
108
|
+
`);
|
|
109
|
+
}, 15e3);
|
|
110
|
+
const cleanup = () => {
|
|
111
|
+
if (closed) return;
|
|
112
|
+
closed = true;
|
|
113
|
+
clearInterval(heartbeat);
|
|
114
|
+
listeners.delete(listener);
|
|
115
|
+
try {
|
|
116
|
+
controller.close();
|
|
117
|
+
} catch {
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const signal = c.req?.raw?.signal;
|
|
121
|
+
if (signal) {
|
|
122
|
+
if (signal.aborted) cleanup();
|
|
123
|
+
else signal.addEventListener("abort", cleanup, { once: true });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return new Response(stream, {
|
|
128
|
+
status: 200,
|
|
129
|
+
headers: {
|
|
130
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
131
|
+
"Cache-Control": "no-cache, no-transform",
|
|
132
|
+
"Connection": "keep-alive",
|
|
133
|
+
"X-Accel-Buffering": "no"
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
app.post(routePath, async (c) => {
|
|
138
|
+
let body = {};
|
|
139
|
+
try {
|
|
140
|
+
const ct = c.req?.header?.("content-type") ?? "";
|
|
141
|
+
if (typeof c.req?.json === "function" && ct.includes("json")) {
|
|
142
|
+
body = await c.req.json();
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
if (onPostReload) await onPostReload(body);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
return new Response(
|
|
150
|
+
JSON.stringify({ ok: false, error: e?.message ?? "reload handler failed" }),
|
|
151
|
+
{ status: 500, headers: { "Content-Type": "application/json" } }
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
const reason = body.reason ?? "manual-trigger";
|
|
155
|
+
broadcast({
|
|
156
|
+
kind: "reload",
|
|
157
|
+
reason,
|
|
158
|
+
changed: body.changed,
|
|
159
|
+
timestamp: Date.now()
|
|
160
|
+
});
|
|
161
|
+
return new Response(
|
|
162
|
+
JSON.stringify({ ok: true, listeners: listeners.size, reason }),
|
|
163
|
+
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
broadcastReload(reason, changed) {
|
|
168
|
+
broadcast({ kind: "reload", reason, changed, timestamp: Date.now() });
|
|
169
|
+
},
|
|
170
|
+
setOnPostReload(fn) {
|
|
171
|
+
onPostReload = fn;
|
|
172
|
+
},
|
|
173
|
+
listenerCount: () => listeners.size
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
var init_hmr_routes = __esm({
|
|
177
|
+
"src/routes/hmr-routes.ts"() {
|
|
178
|
+
"use strict";
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
30
182
|
// src/node.ts
|
|
31
183
|
var node_exports = {};
|
|
32
184
|
__export(node_exports, {
|
|
@@ -1820,6 +1972,21 @@ var _MetadataManager = class _MetadataManager {
|
|
|
1820
1972
|
unsubscribe: () => this.removeWatchCallback(type, wrappedCallback)
|
|
1821
1973
|
};
|
|
1822
1974
|
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Subscribe to raw metadata watch events for a given type.
|
|
1977
|
+
*
|
|
1978
|
+
* Unlike `watchService` (which maps to the IMetadataService contract and
|
|
1979
|
+
* drops fields like `path`/`timestamp`), this returns the raw
|
|
1980
|
+
* `MetadataWatchEvent` produced by the underlying watcher — useful for
|
|
1981
|
+
* developer-facing tooling such as the HMR SSE endpoint that wants the
|
|
1982
|
+
* source file path and original timestamp.
|
|
1983
|
+
*
|
|
1984
|
+
* @returns An unsubscribe function.
|
|
1985
|
+
*/
|
|
1986
|
+
subscribe(type, callback) {
|
|
1987
|
+
this.addWatchCallback(type, callback);
|
|
1988
|
+
return () => this.removeWatchCallback(type, callback);
|
|
1989
|
+
}
|
|
1823
1990
|
// ==========================================
|
|
1824
1991
|
// Import / Export
|
|
1825
1992
|
// ==========================================
|
|
@@ -2835,6 +3002,33 @@ var MetadataPlugin = class {
|
|
|
2835
3002
|
error: e.message
|
|
2836
3003
|
});
|
|
2837
3004
|
}
|
|
3005
|
+
try {
|
|
3006
|
+
const httpServer = ctx.getService("http-server") ?? ctx.getService("http.server");
|
|
3007
|
+
if (httpServer && typeof httpServer.getRawApp === "function") {
|
|
3008
|
+
const { registerMetadataHmrRoutes: registerMetadataHmrRoutes2 } = await Promise.resolve().then(() => (init_hmr_routes(), hmr_routes_exports));
|
|
3009
|
+
const hub = registerMetadataHmrRoutes2(httpServer.getRawApp(), this.manager);
|
|
3010
|
+
hub.setOnPostReload(async (body = {}) => {
|
|
3011
|
+
const src2 = this.options.artifactSource;
|
|
3012
|
+
if (src2?.mode === "local-file") {
|
|
3013
|
+
try {
|
|
3014
|
+
await this._loadFromLocalFile(ctx, src2.path, src2.fetchTimeoutMs);
|
|
3015
|
+
ctx.logger.info("[MetadataPlugin] artifact reloaded via HMR POST", {
|
|
3016
|
+
path: src2.path,
|
|
3017
|
+
reason: body?.reason
|
|
3018
|
+
});
|
|
3019
|
+
} catch (e) {
|
|
3020
|
+
ctx.logger.warn("[MetadataPlugin] artifact reload failed", { error: e?.message });
|
|
3021
|
+
throw e;
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
});
|
|
3025
|
+
console.log("[MetadataPlugin] HMR endpoint registered at /api/v1/dev/metadata-events");
|
|
3026
|
+
} else {
|
|
3027
|
+
console.log("[MetadataPlugin] HTTP server with getRawApp() not available \u2014 skipping HMR endpoint");
|
|
3028
|
+
}
|
|
3029
|
+
} catch (e) {
|
|
3030
|
+
console.warn("[MetadataPlugin] Failed to register HMR endpoint", e?.message);
|
|
3031
|
+
}
|
|
2838
3032
|
};
|
|
2839
3033
|
this.options = {
|
|
2840
3034
|
watch: true,
|