lecodes-cli 2.2.13 → 2.2.14
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.js +207 -48
- package/package.json +8 -8
- package/runtime/sdk-types.json +1 -1
- package/runtime/web/VERSION.json +3 -3
- package/runtime/web/player.js +2 -2
- package/runtime/web-lite/lite.js +1 -1
- package/src/dev/backendWorker.ts +26 -3
- package/src/dev/localBackend.ts +7 -2
- package/src/dev/projectBackend.ts +8 -2
- package/src/platform/api.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -64,7 +64,7 @@ var package_default;
|
|
|
64
64
|
var init_package = __esm(() => {
|
|
65
65
|
package_default = {
|
|
66
66
|
name: "lecodes-cli",
|
|
67
|
-
version: "2.2.
|
|
67
|
+
version: "2.2.14",
|
|
68
68
|
dependencies: {
|
|
69
69
|
"@letary/chisel": "^0.15.0",
|
|
70
70
|
jimp: "^1.6.1",
|
|
@@ -88,7 +88,7 @@ var init_package = __esm(() => {
|
|
|
88
88
|
},
|
|
89
89
|
peerDependencies: {
|
|
90
90
|
"lecodes-design": "^0.11.0",
|
|
91
|
-
"lecodes-headless": "^2.2.
|
|
91
|
+
"lecodes-headless": "^2.2.14",
|
|
92
92
|
"lecodes-3d-editor": "^0.9.0",
|
|
93
93
|
"lecodes-assets": "^0.2.1",
|
|
94
94
|
"heic-decode": "^2.1.0",
|
|
@@ -158,7 +158,7 @@ var init_package = __esm(() => {
|
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
// ../../sdk/src/version.ts
|
|
161
|
-
var SDK_VERSION = "2.2.
|
|
161
|
+
var SDK_VERSION = "2.2.14";
|
|
162
162
|
|
|
163
163
|
// src/cli/args.ts
|
|
164
164
|
var isNegativeNumber = (s) => /^-(\d|\.\d)/.test(s), isValue = (s) => !s.startsWith("-") || isNegativeNumber(s), parseArgv = (argv, booleans = new Set) => {
|
|
@@ -170307,7 +170307,7 @@ var normalizePath2 = (path) => {
|
|
|
170307
170307
|
continue;
|
|
170308
170308
|
const exported = new Map(checker.getExportsOfModule(modSym).map((s) => [s.name, s]));
|
|
170309
170309
|
for (const ex of exports) {
|
|
170310
|
-
if (ex.kind === "other")
|
|
170310
|
+
if (ex.kind === "other" || ex.kind === "push")
|
|
170311
170311
|
continue;
|
|
170312
170312
|
const id = `${serverModuleId(path)}#${ex.name}`;
|
|
170313
170313
|
let sym = exported.get(ex.name);
|
|
@@ -170628,6 +170628,8 @@ var SERVER_FILE, isServerPath = (path) => SERVER_FILE.test(path), serverModuleId
|
|
|
170628
170628
|
const s = init.trimStart();
|
|
170629
170629
|
if (/^channel\s*[<(]/.test(s))
|
|
170630
170630
|
return "channel";
|
|
170631
|
+
if (/^pushChannel\s*[<(]/.test(s))
|
|
170632
|
+
return "push";
|
|
170631
170633
|
if (/^async\s+function\b/.test(s))
|
|
170632
170634
|
return "fn";
|
|
170633
170635
|
if (/^async\b/.test(s))
|
|
@@ -170671,7 +170673,7 @@ var SERVER_FILE, isServerPath = (path) => SERVER_FILE.test(path), serverModuleId
|
|
|
170671
170673
|
}
|
|
170672
170674
|
}
|
|
170673
170675
|
return found.sort((a, b) => a.at - b.at).map(({ name, kind }) => ({ name, kind }));
|
|
170674
|
-
}, serverStubSource = (path, exports, serverUrl) => {
|
|
170676
|
+
}, serverStubSource = (path, exports, serverUrl, push = exports.some((e) => e.kind === "push")) => {
|
|
170675
170677
|
const mod = serverModuleId(path);
|
|
170676
170678
|
const url = JSON.stringify(serverUrl);
|
|
170677
170679
|
const lines = exports.map(({ name, kind }) => {
|
|
@@ -170680,8 +170682,12 @@ var SERVER_FILE, isServerPath = (path) => SERVER_FILE.test(path), serverModuleId
|
|
|
170680
170682
|
return `export const ${name} = __rpc(${url}, ${id})`;
|
|
170681
170683
|
if (kind === "channel")
|
|
170682
170684
|
return `export const ${name} = __channel(${url}, ${id})`;
|
|
170685
|
+
if (kind === "push")
|
|
170686
|
+
return `export const ${name} = __pushChannel(${url}, ${id})`;
|
|
170683
170687
|
return `export const ${name} = __serverOnly(${id})`;
|
|
170684
170688
|
});
|
|
170689
|
+
if (push)
|
|
170690
|
+
lines.unshift("__pushEnable()");
|
|
170685
170691
|
return `// client stub of ${mod} — generated by the lecodes compiler
|
|
170686
170692
|
${lines.join(`
|
|
170687
170693
|
`)}
|
|
@@ -170689,9 +170695,9 @@ ${lines.join(`
|
|
|
170689
170695
|
}, ClientPublishError, clientPublishes = (entries) => {
|
|
170690
170696
|
const channels = new Map;
|
|
170691
170697
|
for (const [path, exports] of Object.entries(scanServerModules(entries))) {
|
|
170692
|
-
const names = exports.filter((e) => e.kind === "channel").map((e) => e.name);
|
|
170693
|
-
if (names.
|
|
170694
|
-
channels.set(path.replace(/\.[tj]s$/, ""),
|
|
170698
|
+
const names = new Map(exports.filter((e) => e.kind === "channel" || e.kind === "push").map((e) => [e.name, e.kind === "push" ? "send" : "publish"]));
|
|
170699
|
+
if (names.size)
|
|
170700
|
+
channels.set(path.replace(/\.[tj]s$/, ""), names);
|
|
170695
170701
|
}
|
|
170696
170702
|
if (channels.size === 0)
|
|
170697
170703
|
return [];
|
|
@@ -170710,17 +170716,18 @@ ${lines.join(`
|
|
|
170710
170716
|
continue;
|
|
170711
170717
|
for (const part of m[1].split(",")) {
|
|
170712
170718
|
const [imported, local] = part.split(/\s+as\s+/).map((s) => s.trim());
|
|
170713
|
-
|
|
170714
|
-
|
|
170719
|
+
const verb = imported ? names.get(imported) : undefined;
|
|
170720
|
+
if (verb)
|
|
170721
|
+
locals.push([local ?? imported, verb]);
|
|
170715
170722
|
}
|
|
170716
170723
|
}
|
|
170717
170724
|
if (!locals.length)
|
|
170718
170725
|
continue;
|
|
170719
170726
|
const code = blankCommentsAndStrings(src);
|
|
170720
|
-
for (const local of locals) {
|
|
170721
|
-
for (const m of code.matchAll(new RegExp(`(?<![\\w$.])${local.replace(/\$/g, "\\$")}\\s*\\.\\s
|
|
170727
|
+
for (const [local, verb] of locals) {
|
|
170728
|
+
for (const m of code.matchAll(new RegExp(`(?<![\\w$.])${local.replace(/\$/g, "\\$")}\\s*\\.\\s*${verb}\\s*\\(`, "g"))) {
|
|
170722
170729
|
out.push(`${serverModuleId(e.path)}:${code.slice(0, m.index).split(`
|
|
170723
|
-
`).length}: ${local}
|
|
170730
|
+
`).length}: ${local}.${verb}(…)`);
|
|
170724
170731
|
}
|
|
170725
170732
|
}
|
|
170726
170733
|
}
|
|
@@ -170760,7 +170767,11 @@ ${lines.join(`
|
|
|
170760
170767
|
out[normalizePath3(e.path)] = scanServerExports(e.text ?? "", serverModuleId(e.path));
|
|
170761
170768
|
}
|
|
170762
170769
|
return out;
|
|
170763
|
-
}, stubServerEntries = (entries, serverUrl) =>
|
|
170770
|
+
}, stubServerEntries = (entries, serverUrl) => {
|
|
170771
|
+
const modules = scanServerModules(entries);
|
|
170772
|
+
const push = Object.values(modules).some((exports) => exports.some((e) => e.kind === "push"));
|
|
170773
|
+
return entries.map((e) => e.type === "text" && isServerPath(e.path) ? { ...e, text: serverStubSource(e.path, modules[normalizePath3(e.path)] ?? [], serverUrl, push) } : e);
|
|
170774
|
+
}, compileServerBundle = async (opts) => {
|
|
170764
170775
|
const modules = scanServerModules(opts.entries);
|
|
170765
170776
|
if (Object.keys(modules).length === 0)
|
|
170766
170777
|
return null;
|
|
@@ -170797,7 +170808,7 @@ var init_serverSplit = __esm(() => {
|
|
|
170797
170808
|
ClientPublishError = class ClientPublishError extends Error {
|
|
170798
170809
|
problems;
|
|
170799
170810
|
constructor(problems) {
|
|
170800
|
-
super(`a channel goes from the server to the app — the app
|
|
170811
|
+
super(`a channel goes from the server to the app — the app listens; to send, call a server function that publishes (a push channel: that sends):
|
|
170801
170812
|
${problems.join(`
|
|
170802
170813
|
`)}`);
|
|
170803
170814
|
this.name = "ClientPublishError";
|
|
@@ -207697,15 +207708,26 @@ var init_channel = __esm(() => {
|
|
|
207697
207708
|
seam = globalThis;
|
|
207698
207709
|
});
|
|
207699
207710
|
|
|
207711
|
+
// ../../sdk/src/server/pushChannel.ts
|
|
207712
|
+
var seam2, setPushSender = (sender) => {
|
|
207713
|
+
if (sender)
|
|
207714
|
+
seam2.__lecodesPushSend = sender;
|
|
207715
|
+
else
|
|
207716
|
+
delete seam2.__lecodesPushSend;
|
|
207717
|
+
}, isPushChannel = (v) => typeof v === "object" && v !== null && v.__pushChannel === true;
|
|
207718
|
+
var init_pushChannel = __esm(() => {
|
|
207719
|
+
seam2 = globalThis;
|
|
207720
|
+
});
|
|
207721
|
+
|
|
207700
207722
|
// ../../sdk/src/server/context.ts
|
|
207701
|
-
var
|
|
207723
|
+
var seam3, setRequestProvider = (provider) => {
|
|
207702
207724
|
if (provider)
|
|
207703
|
-
|
|
207725
|
+
seam3.__lecodesRequest = provider;
|
|
207704
207726
|
else
|
|
207705
|
-
delete
|
|
207706
|
-
}, currentRequest = () =>
|
|
207727
|
+
delete seam3.__lecodesRequest;
|
|
207728
|
+
}, currentRequest = () => seam3.__lecodesRequest?.();
|
|
207707
207729
|
var init_context2 = __esm(() => {
|
|
207708
|
-
|
|
207730
|
+
seam3 = globalThis;
|
|
207709
207731
|
});
|
|
207710
207732
|
|
|
207711
207733
|
// ../../sdk/src/server/db/fields.ts
|
|
@@ -207793,30 +207815,30 @@ var FILE_MODEL = "File", filePublicFields = () => ({
|
|
|
207793
207815
|
width: t.int().optional(),
|
|
207794
207816
|
height: t.int().optional(),
|
|
207795
207817
|
createdAt: t.date().default("now")
|
|
207796
|
-
}),
|
|
207818
|
+
}), seam4, setFilesSeam = (value) => {
|
|
207797
207819
|
if (value)
|
|
207798
|
-
|
|
207820
|
+
seam4.__lecodesFiles = value;
|
|
207799
207821
|
else
|
|
207800
|
-
delete
|
|
207822
|
+
delete seam4.__lecodesFiles;
|
|
207801
207823
|
};
|
|
207802
207824
|
var init_models2 = __esm(() => {
|
|
207803
207825
|
init_fields();
|
|
207804
|
-
|
|
207826
|
+
seam4 = globalThis;
|
|
207805
207827
|
});
|
|
207806
207828
|
|
|
207807
207829
|
// ../../sdk/src/server/db/defineDb.ts
|
|
207808
|
-
var
|
|
207830
|
+
var seam5, setDbTransport = (transport) => {
|
|
207809
207831
|
if (transport)
|
|
207810
|
-
|
|
207832
|
+
seam5.__lecodesDbTransport = transport;
|
|
207811
207833
|
else
|
|
207812
|
-
delete
|
|
207834
|
+
delete seam5.__lecodesDbTransport;
|
|
207813
207835
|
}, takeRegisteredDbs = () => {
|
|
207814
|
-
const dbs =
|
|
207815
|
-
|
|
207836
|
+
const dbs = seam5.__lecodesDbs ?? [];
|
|
207837
|
+
seam5.__lecodesDbs = [];
|
|
207816
207838
|
return dbs;
|
|
207817
207839
|
};
|
|
207818
207840
|
var init_defineDb = __esm(() => {
|
|
207819
|
-
|
|
207841
|
+
seam5 = globalThis;
|
|
207820
207842
|
});
|
|
207821
207843
|
|
|
207822
207844
|
// ../../sdk/src/server/validate.ts
|
|
@@ -207931,7 +207953,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
207931
207953
|
var isDb = (v) => typeof v === "object" && v !== null && typeof v.$schema === "string", loadServerModules = (reg = globalThis.__lecodesServer) => {
|
|
207932
207954
|
if (!reg)
|
|
207933
207955
|
throw new Error("loadServerModules: no server bundle registered (globalThis.__lecodesServer)");
|
|
207934
|
-
const out = { endpoints: new Map, channels: new Map, dbs: [], manifest: reg.manifest };
|
|
207956
|
+
const out = { endpoints: new Map, channels: new Map, pushChannels: new Map, dbs: [], manifest: reg.manifest };
|
|
207935
207957
|
for (const [mod, exports] of Object.entries(reg.modules)) {
|
|
207936
207958
|
const kinds = new Map((reg.manifest?.modules?.[mod] ?? []).map((e) => [e.name, e.kind]));
|
|
207937
207959
|
for (const [name, value] of Object.entries(exports)) {
|
|
@@ -207942,6 +207964,9 @@ var isDb = (v) => typeof v === "object" && v !== null && typeof v.$schema === "s
|
|
|
207942
207964
|
} else if (isChannel(value)) {
|
|
207943
207965
|
value.__id = id;
|
|
207944
207966
|
out.channels.set(id, value);
|
|
207967
|
+
} else if (isPushChannel(value)) {
|
|
207968
|
+
value.__id = id;
|
|
207969
|
+
out.pushChannels.set(id, value);
|
|
207945
207970
|
} else if (isDb(value))
|
|
207946
207971
|
out.dbs.push(value);
|
|
207947
207972
|
}
|
|
@@ -207961,9 +207986,10 @@ var isDb = (v) => typeof v === "object" && v !== null && typeof v.$schema === "s
|
|
|
207961
207986
|
if (name !== "MarciEmbeddedError" && name !== "MarciHttpError" || typeof kind !== "string")
|
|
207962
207987
|
return null;
|
|
207963
207988
|
return DB_ERROR_STATUS[kind] ?? null;
|
|
207964
|
-
}, als, installProvider = () => setRequestProvider(() => als.getStore()),
|
|
207965
|
-
const
|
|
207966
|
-
|
|
207989
|
+
}, als, installProvider = () => setRequestProvider(() => als.getStore()), envelope = (server2) => (r, rc) => {
|
|
207990
|
+
const s = rc.auth;
|
|
207991
|
+
const out = s?.issuedToken ? { ...r, session: s.issuedToken } : r;
|
|
207992
|
+
return s && s.userId !== null && !s.pushAddress && server2.pushChannels.size ? { ...out, push: true } : out;
|
|
207967
207993
|
}, createInvoker = (server2, opts = {}) => {
|
|
207968
207994
|
installProvider();
|
|
207969
207995
|
const validate = opts.validate ?? true;
|
|
@@ -207971,6 +207997,7 @@ var isDb = (v) => typeof v === "object" && v !== null && typeof v.$schema === "s
|
|
|
207971
207997
|
const params = server2.manifest.params;
|
|
207972
207998
|
const auth = opts.auth ?? null;
|
|
207973
207999
|
const files = opts.files ?? null;
|
|
208000
|
+
const withSession = envelope(server2);
|
|
207974
208001
|
return async (id, args, ctx = { headers: {} }) => {
|
|
207975
208002
|
const fn = server2.endpoints.get(id);
|
|
207976
208003
|
if (!fn)
|
|
@@ -208037,6 +208064,7 @@ var isDb = (v) => typeof v === "object" && v !== null && typeof v.$schema === "s
|
|
|
208037
208064
|
const onError = opts.onError ?? ((id, e) => console.error(`[server] ${id}:`, e));
|
|
208038
208065
|
const params = server2.manifest.params;
|
|
208039
208066
|
const auth = opts.auth ?? null;
|
|
208067
|
+
const withSession = envelope(server2);
|
|
208040
208068
|
return async (channelId, args = [], ctx = { headers: {} }) => {
|
|
208041
208069
|
const ch = server2.channels.get(channelId);
|
|
208042
208070
|
if (!ch)
|
|
@@ -208069,6 +208097,7 @@ var isDb = (v) => typeof v === "object" && v !== null && typeof v.$schema === "s
|
|
|
208069
208097
|
};
|
|
208070
208098
|
var init_runtime = __esm(() => {
|
|
208071
208099
|
init_channel();
|
|
208100
|
+
init_pushChannel();
|
|
208072
208101
|
init_context2();
|
|
208073
208102
|
init_defineDb();
|
|
208074
208103
|
init_validate();
|
|
@@ -208231,7 +208260,12 @@ var CODE_TTL_MS, CODE_MAX_ATTEMPTS = 5, SEND_MIN_GAP_MS = 30000, SEND_MAX_PER_10
|
|
|
208231
208260
|
if (!LOGIN_RE.test(l))
|
|
208232
208261
|
throw new ApiError2(400, "Login must be 3–32 letters, digits, dots, dashes or underscores");
|
|
208233
208262
|
return { provider: "login", subject: l.toLowerCase() };
|
|
208234
|
-
}, identityKey = (provider, subject) => `${provider}:${subject}`,
|
|
208263
|
+
}, identityKey = (provider, subject) => `${provider}:${subject}`, PUSH_ADDRESS_HEADER = "x-lecodes-push", PUSH_ADDRESS_RE, pushAddressOf = (ctx) => {
|
|
208264
|
+
const headers = ctx.headers ?? {};
|
|
208265
|
+
const raw = headers[PUSH_ADDRESS_HEADER] ?? Object.entries(headers).find(([k]) => k.toLowerCase() === PUSH_ADDRESS_HEADER)?.[1];
|
|
208266
|
+
const value = typeof raw === "string" ? raw.trim() : "";
|
|
208267
|
+
return PUSH_ADDRESS_RE.test(value) ? value : null;
|
|
208268
|
+
}, window2 = (map, key, now, span) => {
|
|
208235
208269
|
const list = (map.get(key) ?? []).filter((x) => now - x < span);
|
|
208236
208270
|
map.set(key, list);
|
|
208237
208271
|
return list;
|
|
@@ -208262,9 +208296,10 @@ var CODE_TTL_MS, CODE_MAX_ATTEMPTS = 5, SEND_MIN_GAP_MS = 30000, SEND_MAX_PER_10
|
|
|
208262
208296
|
};
|
|
208263
208297
|
const mint = async (ctx) => {
|
|
208264
208298
|
const token = randomToken();
|
|
208265
|
-
const
|
|
208266
|
-
const
|
|
208267
|
-
|
|
208299
|
+
const pushAddress = pushAddressOf(ctx);
|
|
208300
|
+
const { id } = await sessions.insert({ tokenHash: await sha2562(token), ...pushAddress ? { pushAddress } : {} });
|
|
208301
|
+
const state = { sessionId: id, userId: null, pushAddress, issuedToken: token };
|
|
208302
|
+
sessionCache.set(token, { sessionId: id, userId: null, pushAddress, at: now() });
|
|
208268
208303
|
ctx.auth = state;
|
|
208269
208304
|
ctx.sessionToken = token;
|
|
208270
208305
|
return state;
|
|
@@ -208285,6 +208320,15 @@ var CODE_TTL_MS, CODE_MAX_ATTEMPTS = 5, SEND_MIN_GAP_MS = 30000, SEND_MAX_PER_10
|
|
|
208285
208320
|
if (opts.rotate)
|
|
208286
208321
|
await rotate(ctx);
|
|
208287
208322
|
};
|
|
208323
|
+
const followPushAddress = async (token, sessionId, held, told) => {
|
|
208324
|
+
if (!told || told === held)
|
|
208325
|
+
return held;
|
|
208326
|
+
await sessions.update(sessionId, { pushAddress: told });
|
|
208327
|
+
const c = sessionCache.get(token);
|
|
208328
|
+
if (c)
|
|
208329
|
+
c.pushAddress = told;
|
|
208330
|
+
return told;
|
|
208331
|
+
};
|
|
208288
208332
|
const resolve = async (ctx) => {
|
|
208289
208333
|
if (!tables)
|
|
208290
208334
|
return;
|
|
@@ -208292,16 +208336,18 @@ var CODE_TTL_MS, CODE_MAX_ATTEMPTS = 5, SEND_MIN_GAP_MS = 30000, SEND_MAX_PER_10
|
|
|
208292
208336
|
if (token) {
|
|
208293
208337
|
const c = sessionCache.get(token);
|
|
208294
208338
|
if (c && now() - c.at < CACHE_TTL_MS) {
|
|
208295
|
-
|
|
208339
|
+
const pushAddress = await followPushAddress(token, c.sessionId, c.pushAddress, pushAddressOf(ctx));
|
|
208340
|
+
ctx.auth = { sessionId: c.sessionId, userId: c.userId, pushAddress };
|
|
208296
208341
|
return;
|
|
208297
208342
|
}
|
|
208298
|
-
const row = await sessions.where({ tokenHash: await sha2562(token) }).select({ id: true, revoked: true, lastSeenAt: true, user: { id: true } }).first();
|
|
208343
|
+
const row = await sessions.where({ tokenHash: await sha2562(token) }).select({ id: true, revoked: true, lastSeenAt: true, pushAddress: true, user: { id: true } }).first();
|
|
208299
208344
|
if (row && !row.revoked) {
|
|
208300
208345
|
const userId = row.user ? row.user.id : null;
|
|
208301
208346
|
if (now() - (row.lastSeenAt ?? 0) > SEEN_UPDATE_MS)
|
|
208302
208347
|
sessions.update(row.id, { lastSeenAt: now() }).then(undefined, () => {});
|
|
208303
|
-
sessionCache.set(token, { sessionId: row.id, userId, at: now() });
|
|
208304
|
-
|
|
208348
|
+
sessionCache.set(token, { sessionId: row.id, userId, pushAddress: row.pushAddress ?? null, at: now() });
|
|
208349
|
+
const pushAddress = await followPushAddress(token, row.id, row.pushAddress ?? null, pushAddressOf(ctx));
|
|
208350
|
+
ctx.auth = { sessionId: row.id, userId, pushAddress };
|
|
208305
208351
|
return;
|
|
208306
208352
|
}
|
|
208307
208353
|
}
|
|
@@ -208493,6 +208539,92 @@ var init_host = __esm(() => {
|
|
|
208493
208539
|
enc = new TextEncoder;
|
|
208494
208540
|
EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
208495
208541
|
LOGIN_RE = /^[\p{L}\p{N}_.-]{3,32}$/u;
|
|
208542
|
+
PUSH_ADDRESS_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
208543
|
+
});
|
|
208544
|
+
|
|
208545
|
+
// ../../sdk/src/server/push/host.ts
|
|
208546
|
+
var PUSH_BATCH = 500, chunks = (list, size) => {
|
|
208547
|
+
const out = [];
|
|
208548
|
+
for (let i = 0;i < list.length; i += size)
|
|
208549
|
+
out.push(list.slice(i, i + size));
|
|
208550
|
+
return out;
|
|
208551
|
+
}, createPushHost = (cfg) => {
|
|
208552
|
+
const sessions = cfg.db?.$auth?.session ?? null;
|
|
208553
|
+
const relay = cfg.relay ?? null;
|
|
208554
|
+
const log = cfg.log ?? ((level, text) => level === "warn" ? console.warn(text) : console.info(text));
|
|
208555
|
+
const warned = new Set;
|
|
208556
|
+
const devices = async (userIds) => {
|
|
208557
|
+
const rows = await sessions.where({ user: { id: { $in: userIds } }, revoked: false }).select({ id: true, pushAddress: true });
|
|
208558
|
+
const byAddress = new Map;
|
|
208559
|
+
for (const row of rows) {
|
|
208560
|
+
if (!row.pushAddress)
|
|
208561
|
+
continue;
|
|
208562
|
+
const list = byAddress.get(row.pushAddress) ?? [];
|
|
208563
|
+
list.push(row.id);
|
|
208564
|
+
byAddress.set(row.pushAddress, list);
|
|
208565
|
+
}
|
|
208566
|
+
return byAddress;
|
|
208567
|
+
};
|
|
208568
|
+
const forget = async (byAddress, addresses) => {
|
|
208569
|
+
const ids = addresses.flatMap((a) => byAddress.get(a) ?? []);
|
|
208570
|
+
if (!ids.length)
|
|
208571
|
+
return;
|
|
208572
|
+
await sessions.where({ id: { $in: ids } }).updateMany({ pushAddress: null });
|
|
208573
|
+
};
|
|
208574
|
+
const send = async (channelId, userIds, message) => {
|
|
208575
|
+
if (!sessions) {
|
|
208576
|
+
throw new Error("pushChannel.send: the project's database has no sign-in — a user's devices are the sessions of defineDb({...}).withAuth({ model }), without it there is no one to send to");
|
|
208577
|
+
}
|
|
208578
|
+
if (!relay) {
|
|
208579
|
+
if (!warned.has(channelId)) {
|
|
208580
|
+
warned.add(channelId);
|
|
208581
|
+
log("warn", `${channelId}: notifications are not sent from this backend (no road to the platform's sender) — a deployed backend sends them`);
|
|
208582
|
+
}
|
|
208583
|
+
return { sent: 0 };
|
|
208584
|
+
}
|
|
208585
|
+
const byAddress = await devices(userIds);
|
|
208586
|
+
if (byAddress.size === 0)
|
|
208587
|
+
return { sent: 0 };
|
|
208588
|
+
const wire = {
|
|
208589
|
+
channel: channelId,
|
|
208590
|
+
title: message.title,
|
|
208591
|
+
...message.body !== undefined ? { body: message.body } : {},
|
|
208592
|
+
...message.url !== undefined ? { url: message.url } : {},
|
|
208593
|
+
...message.data !== undefined ? { data: message.data } : {},
|
|
208594
|
+
...message.badge !== undefined ? { badge: message.badge } : {}
|
|
208595
|
+
};
|
|
208596
|
+
let sent = 0;
|
|
208597
|
+
for (let batch of chunks([...byAddress.keys()], PUSH_BATCH)) {
|
|
208598
|
+
let result = await relay(batch, wire);
|
|
208599
|
+
if (result.unknown?.length) {
|
|
208600
|
+
const unknown = new Set(result.unknown);
|
|
208601
|
+
await forget(byAddress, [...unknown]);
|
|
208602
|
+
batch = batch.filter((a) => !unknown.has(a));
|
|
208603
|
+
if (!batch.length)
|
|
208604
|
+
continue;
|
|
208605
|
+
result = await relay(batch, wire);
|
|
208606
|
+
if (result.unknown?.length)
|
|
208607
|
+
await forget(byAddress, result.unknown);
|
|
208608
|
+
}
|
|
208609
|
+
sent += result.sent;
|
|
208610
|
+
const dead = result.failed.filter((f) => f.reason === "disabled").map((f) => f.address);
|
|
208611
|
+
if (dead.length)
|
|
208612
|
+
await forget(byAddress, dead);
|
|
208613
|
+
}
|
|
208614
|
+
return { sent };
|
|
208615
|
+
};
|
|
208616
|
+
return {
|
|
208617
|
+
get enabled() {
|
|
208618
|
+
return relay !== null;
|
|
208619
|
+
},
|
|
208620
|
+
install() {
|
|
208621
|
+
setPushSender(send);
|
|
208622
|
+
},
|
|
208623
|
+
send
|
|
208624
|
+
};
|
|
208625
|
+
};
|
|
208626
|
+
var init_host2 = __esm(() => {
|
|
208627
|
+
init_pushChannel();
|
|
208496
208628
|
});
|
|
208497
208629
|
|
|
208498
208630
|
// ../../sdk/src/server/files/host.ts
|
|
@@ -208891,7 +209023,7 @@ var UploadError, UUID, JOURNAL = "lecodes-files", MB, TMP_MAX_AGE_MS, MAX_IMAGE_
|
|
|
208891
209023
|
}
|
|
208892
209024
|
};
|
|
208893
209025
|
};
|
|
208894
|
-
var
|
|
209026
|
+
var init_host3 = __esm(() => {
|
|
208895
209027
|
init_context2();
|
|
208896
209028
|
init_models2();
|
|
208897
209029
|
UploadError = class UploadError extends Error {
|
|
@@ -208964,15 +209096,17 @@ var describeField = (f) => {
|
|
|
208964
209096
|
models,
|
|
208965
209097
|
endpoints: [...server2.endpoints.keys()].map((id) => ({ id, params: params[id] ?? null })),
|
|
208966
209098
|
channels: [...server2.channels.keys()],
|
|
209099
|
+
pushChannels: [...server2.pushChannels.keys()],
|
|
208967
209100
|
auth: { model: db?.$auth?.model ?? null },
|
|
208968
209101
|
appName: server2.manifest.app?.name
|
|
208969
209102
|
};
|
|
208970
209103
|
};
|
|
208971
|
-
var
|
|
209104
|
+
var init_host4 = __esm(() => {
|
|
208972
209105
|
init_runtime();
|
|
208973
209106
|
init_defineDb();
|
|
208974
209107
|
init_host();
|
|
208975
209108
|
init_host2();
|
|
209109
|
+
init_host3();
|
|
208976
209110
|
init_models2();
|
|
208977
209111
|
init_models();
|
|
208978
209112
|
});
|
|
@@ -210046,6 +210180,16 @@ var post = (m) => {
|
|
|
210046
210180
|
await db.$sync(schema);
|
|
210047
210181
|
return [`database started over — the schema change couldn't be migrated (${reason}); the previous data is in ${aside}`];
|
|
210048
210182
|
}
|
|
210183
|
+
}, pushRelay = (sender) => async (to, message) => {
|
|
210184
|
+
try {
|
|
210185
|
+
return await sendPush(sender.apiUrl, sender.token, sender.uuid, { to, ...message });
|
|
210186
|
+
} catch (e) {
|
|
210187
|
+
const body = e instanceof ApiError ? e.body : null;
|
|
210188
|
+
if (body?.code === "unknown_addresses" && Array.isArray(body.addresses)) {
|
|
210189
|
+
return { sent: 0, failed: [], unknown: body.addresses.filter((a) => typeof a === "string") };
|
|
210190
|
+
}
|
|
210191
|
+
throw new Error(`push: the platform refused the send: ${e.message}`);
|
|
210192
|
+
}
|
|
210049
210193
|
}, load = async (m) => {
|
|
210050
210194
|
const noDb = () => {
|
|
210051
210195
|
throw new Error("db: the database is not open yet — query it inside an endpoint, not while the module loads");
|
|
@@ -210064,6 +210208,11 @@ var post = (m) => {
|
|
|
210064
210208
|
log: (level, text) => post({ t: "log", level, text })
|
|
210065
210209
|
});
|
|
210066
210210
|
authHost.install();
|
|
210211
|
+
createPushHost({
|
|
210212
|
+
db: server2.dbs.find((d) => d.$auth) ?? null,
|
|
210213
|
+
relay: m.push ? pushRelay(m.push) : null,
|
|
210214
|
+
log: (level, text) => post({ t: "log", level, text })
|
|
210215
|
+
}).install();
|
|
210067
210216
|
const auth = authHost.enabled ? authHost : null;
|
|
210068
210217
|
const onError = (id, e) => post({ t: "log", level: "error", text: `${id}: ${e?.stack ?? e}` });
|
|
210069
210218
|
const files = createFilesHost({
|
|
@@ -210086,8 +210235,9 @@ var post = (m) => {
|
|
|
210086
210235
|
post({ t: "loaded", describe, notes });
|
|
210087
210236
|
};
|
|
210088
210237
|
var init_backendWorker = __esm(() => {
|
|
210089
|
-
|
|
210238
|
+
init_host4();
|
|
210090
210239
|
init_peerInstall();
|
|
210240
|
+
init_api();
|
|
210091
210241
|
console.log = hook("log");
|
|
210092
210242
|
console.info = hook("info");
|
|
210093
210243
|
console.warn = hook("warn");
|
|
@@ -217057,10 +217207,11 @@ init_cli();
|
|
|
217057
217207
|
import { basename as basename14 } from "node:path";
|
|
217058
217208
|
|
|
217059
217209
|
// src/dev/projectBackend.ts
|
|
217060
|
-
|
|
217210
|
+
init_host4();
|
|
217061
217211
|
init_projectCompile();
|
|
217062
217212
|
init_peerInstall();
|
|
217063
217213
|
init_manifest();
|
|
217214
|
+
init_shared();
|
|
217064
217215
|
import { rmSync as rmSync9 } from "node:fs";
|
|
217065
217216
|
import { join as join35, relative as relative5 } from "node:path";
|
|
217066
217217
|
|
|
@@ -217153,7 +217304,7 @@ var startLocalBackend = (options) => {
|
|
|
217153
217304
|
log(`[server:error] the server process exited (${status ?? "killed"}) — it starts again with the next call`);
|
|
217154
217305
|
}
|
|
217155
217306
|
});
|
|
217156
|
-
child.send({ t: "load", code: bundle, dbDir, filesDir, root: options.root });
|
|
217307
|
+
child.send({ t: "load", code: bundle, dbDir, filesDir, root: options.root, push: options.push ?? null });
|
|
217157
217308
|
});
|
|
217158
217309
|
const stop = async (l) => {
|
|
217159
217310
|
if (live === l)
|
|
@@ -217514,7 +217665,15 @@ var createProjectBackend = (options) => {
|
|
|
217514
217665
|
subscribe: (_scope, ch, args, ctx) => backend ? backend.subscribe(ch, args, ctx) : Promise.resolve({ ok: false, status: 404, message: "The project has no server files" })
|
|
217515
217666
|
});
|
|
217516
217667
|
const sockets = new Set;
|
|
217517
|
-
const
|
|
217668
|
+
const push = (() => {
|
|
217669
|
+
try {
|
|
217670
|
+
const { apiUrl, token } = session();
|
|
217671
|
+
return { apiUrl, token, uuid: readManifest(root).uuid };
|
|
217672
|
+
} catch {
|
|
217673
|
+
return null;
|
|
217674
|
+
}
|
|
217675
|
+
})();
|
|
217676
|
+
const start = () => startLocalBackend({ root, dbDir, log, push, onPublish: (ch, group, data) => hub.publish("", ch, group, data) });
|
|
217518
217677
|
const envelope = (body) => new Response(JSON.stringify(body), { status: 200, headers: { "content-type": "application/json", "cache-control": "no-store", ...CORS } });
|
|
217519
217678
|
return {
|
|
217520
217679
|
compile: async (entries) => {
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lecodes-cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.14",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@letary/chisel": "^0.15.0",
|
|
6
6
|
"jimp": "^1.6.1",
|
|
7
|
-
"lecodes-sdk": "2.2.
|
|
7
|
+
"lecodes-sdk": "2.2.14"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"lecodes-design": "https://storage.yandexcloud.net/le-codes/releases/packages/lecodes-design/lecodes-design-0.11.0.tgz",
|
|
11
|
-
"lecodes-headless": "2.2.
|
|
11
|
+
"lecodes-headless": "2.2.14",
|
|
12
12
|
"qrcode-terminal": "^0.12.0",
|
|
13
13
|
"lecodes-3d-editor": "https://storage.yandexcloud.net/le-codes/releases/packages/lecodes-3d-editor/lecodes-3d-editor-0.9.0.tgz",
|
|
14
14
|
"lecodes-assets": "0.2.1",
|
|
15
15
|
"lecodes-creator-nav": "0.19.0",
|
|
16
|
-
"lecodes-gl-lite": "2.2.
|
|
17
|
-
"lecodes-web-frame": "2.2.
|
|
18
|
-
"lecodes-web-player": "2.2.
|
|
19
|
-
"lecodes-web-shared": "2.2.
|
|
16
|
+
"lecodes-gl-lite": "2.2.14",
|
|
17
|
+
"lecodes-web-frame": "2.2.14",
|
|
18
|
+
"lecodes-web-player": "2.2.14",
|
|
19
|
+
"lecodes-web-shared": "2.2.14",
|
|
20
20
|
"lecodes-web-lite": "2.0.2",
|
|
21
21
|
"heic-decode": "^2.1.0",
|
|
22
22
|
"marcidb-embedded": "^0.15.0",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"lecodes-design": "^0.11.0",
|
|
27
|
-
"lecodes-headless": "^2.2.
|
|
27
|
+
"lecodes-headless": "^2.2.14",
|
|
28
28
|
"lecodes-3d-editor": "^0.9.0",
|
|
29
29
|
"lecodes-assets": "^0.2.1",
|
|
30
30
|
"heic-decode": "^2.1.0",
|