deepspace 0.4.5 → 0.5.1
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/README.md +90 -0
- package/dist/cli.js +3590 -1485
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +876 -3664
- package/dist/index.js +511 -366
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +132 -61
- package/dist/server.js +149 -110
- package/dist/server.js.map +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +128 -59
- package/dist/worker.js +144 -99
- package/dist/worker.js.map +1 -1
- package/features/admin-page/src/AdminPage.tsx +3 -5
- package/features/canvas/src/CanvasEditorPage.tsx +0 -2
- package/features/canvas/src/components/CanvasView.tsx +1 -1
- package/features/docs/src/LibrarySidebar.tsx +7 -1
- package/features/docs/src/editor/useDocEditor.ts +5 -1
- package/features/docs/src/use-yjs-room-with-awareness.ts +4 -0
- package/features/file-attachments/src/AttachmentsPage.tsx +7 -1
- package/features/file-attachments/src/useFilePreview.ts +7 -5
- package/features/file-manager/src/FileManagerPage.tsx +2 -3
- package/features/integration-test/feature.json +10 -3
- package/features/integration-test/src/IntegrationTestPage.tsx +15 -12
- package/features/landing/src/LandingPage.tsx +1 -1
- package/features/landing/src/sections/FeaturesGridSection.tsx +0 -92
- package/features/messaging/src/ChatPage.tsx +6 -1
- package/features/messaging/src/components/chat/MessageItem.tsx +5 -1
- package/features/messaging/src/hooks/useChatChannel.ts +23 -7
- package/features/presence-test/feature.json +2 -1
- package/features/sidebar/src/AppSidebar.tsx +1 -1
- package/features/tasks/src/TasksPage.tsx +1 -1
- package/features/testing/feature.json +2 -1
- package/features/testing/src/TestPage.tsx +8 -8
- package/package.json +8 -4
- package/scripts/add-feature.cjs +296 -282
- package/dist/testing.d.ts +0 -115
package/dist/server.js
CHANGED
|
@@ -475,7 +475,8 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
|
475
475
|
if (opts?.where) params.where = opts.where;
|
|
476
476
|
if (opts?.limit) params.limit = opts.limit;
|
|
477
477
|
const data = await executeTool3("records.query", params);
|
|
478
|
-
|
|
478
|
+
const records2 = data?.records;
|
|
479
|
+
return records2 ?? [];
|
|
479
480
|
},
|
|
480
481
|
async create(collection, data) {
|
|
481
482
|
return executeTool3("records.create", { collection, data });
|
|
@@ -632,7 +633,8 @@ async function composioTools(env, options) {
|
|
|
632
633
|
if (!list.ok || !list.success) {
|
|
633
634
|
throw new Error(`composioTools: failed to list Composio tools: ${list.detail}`);
|
|
634
635
|
}
|
|
635
|
-
const
|
|
636
|
+
const listItems = list.data?.items;
|
|
637
|
+
const items = Array.isArray(listItems) ? listItems : [];
|
|
636
638
|
const tools = {};
|
|
637
639
|
for (const item of items) {
|
|
638
640
|
if (!item?.slug) continue;
|
|
@@ -667,13 +669,19 @@ async function composioTools(env, options) {
|
|
|
667
669
|
return tools;
|
|
668
670
|
}
|
|
669
671
|
|
|
672
|
+
// src/server/utils/app-identity.ts
|
|
673
|
+
function appendAppIdentity(headers, env) {
|
|
674
|
+
headers.delete("x-app-identity-token");
|
|
675
|
+
headers.delete("x-app-name");
|
|
676
|
+
if (!env.APP_IDENTITY_TOKEN) return;
|
|
677
|
+
headers.set("x-app-identity-token", env.APP_IDENTITY_TOKEN);
|
|
678
|
+
headers.set("x-app-name", env.APP_NAME);
|
|
679
|
+
}
|
|
680
|
+
|
|
670
681
|
// src/server/utils/screenshot.ts
|
|
671
682
|
async function captureScreenshot(env, opts) {
|
|
672
|
-
const headers = new Headers({
|
|
673
|
-
|
|
674
|
-
"x-app-identity-token": env.APP_IDENTITY_TOKEN,
|
|
675
|
-
"x-app-name": env.APP_NAME
|
|
676
|
-
});
|
|
683
|
+
const headers = new Headers({ "content-type": "application/json" });
|
|
684
|
+
appendAppIdentity(headers, env);
|
|
677
685
|
const res = await platformWorkerFetch(
|
|
678
686
|
env,
|
|
679
687
|
new Request("https://platform-internal/internal/screenshot", {
|
|
@@ -1333,7 +1341,7 @@ var BaseRoom = class {
|
|
|
1333
1341
|
console.error(`[${this.constructor.name}] Message error:`, e);
|
|
1334
1342
|
}
|
|
1335
1343
|
}
|
|
1336
|
-
async webSocketClose(ws,
|
|
1344
|
+
async webSocketClose(ws, _code, _reason) {
|
|
1337
1345
|
const attachment = ws.deserializeAttachment();
|
|
1338
1346
|
if (attachment) {
|
|
1339
1347
|
try {
|
|
@@ -1358,12 +1366,12 @@ var BaseRoom = class {
|
|
|
1358
1366
|
* Return an augmented attachment to serialize on the WebSocket,
|
|
1359
1367
|
* or void to use the default attachment.
|
|
1360
1368
|
*/
|
|
1361
|
-
onConnect(
|
|
1369
|
+
onConnect(_ws, _user) {
|
|
1362
1370
|
}
|
|
1363
1371
|
/**
|
|
1364
1372
|
* Called when a WebSocket disconnects.
|
|
1365
1373
|
*/
|
|
1366
|
-
onDisconnect(
|
|
1374
|
+
onDisconnect(_ws, _user) {
|
|
1367
1375
|
}
|
|
1368
1376
|
// ==========================================================================
|
|
1369
1377
|
// Utilities
|
|
@@ -1611,7 +1619,7 @@ function coerceValue(value, storage, interpretation) {
|
|
|
1611
1619
|
if (m) return parseFloat(m[1]) / 100;
|
|
1612
1620
|
}
|
|
1613
1621
|
if (interpretation.kind === "currency") {
|
|
1614
|
-
const cleaned2 = s.replace(/[^0-9
|
|
1622
|
+
const cleaned2 = s.replace(/[^0-9.-]/g, "");
|
|
1615
1623
|
const n2 = parseFloat(cleaned2);
|
|
1616
1624
|
if (!isNaN(n2)) return n2;
|
|
1617
1625
|
return s;
|
|
@@ -1801,9 +1809,6 @@ var SchemaRegistry = class {
|
|
|
1801
1809
|
has(name) {
|
|
1802
1810
|
return this.trusted.has(name);
|
|
1803
1811
|
}
|
|
1804
|
-
hasTrusted(name) {
|
|
1805
|
-
return this.trusted.has(name);
|
|
1806
|
-
}
|
|
1807
1812
|
all() {
|
|
1808
1813
|
return Array.from(this.trusted.values());
|
|
1809
1814
|
}
|
|
@@ -2118,7 +2123,7 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
2118
2123
|
const columns = getResolvedColumns(schema);
|
|
2119
2124
|
const existing = getRecord(ctx.sql, collection, recordId, schema);
|
|
2120
2125
|
const isUpdate = existing !== null;
|
|
2121
|
-
|
|
2126
|
+
const mergedData = isUpdate ? { ...existing.data, ...data } : { ...data };
|
|
2122
2127
|
for (const col of columns) {
|
|
2123
2128
|
if (col.readonly) continue;
|
|
2124
2129
|
if (!isUpdate) {
|
|
@@ -2173,7 +2178,10 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
2173
2178
|
const permCtx = ctx.getPermissionContext();
|
|
2174
2179
|
if (isUpdate) {
|
|
2175
2180
|
if (!canUpdate(schema, userRole, { ...existing, recordId }, userId, permCtx)) {
|
|
2176
|
-
return {
|
|
2181
|
+
return {
|
|
2182
|
+
success: false,
|
|
2183
|
+
error: `UPDATE DENIED: role=${userRole}, collection=${collection}`
|
|
2184
|
+
};
|
|
2177
2185
|
}
|
|
2178
2186
|
const fieldError = checkFieldPermissions(schema, userRole, finalData, existing.data);
|
|
2179
2187
|
if (fieldError) {
|
|
@@ -2181,7 +2189,10 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
2181
2189
|
}
|
|
2182
2190
|
} else {
|
|
2183
2191
|
if (!canCreate(schema, userRole)) {
|
|
2184
|
-
return {
|
|
2192
|
+
return {
|
|
2193
|
+
success: false,
|
|
2194
|
+
error: `CREATE DENIED: role=${userRole}, collection=${collection}`
|
|
2195
|
+
};
|
|
2185
2196
|
}
|
|
2186
2197
|
}
|
|
2187
2198
|
}
|
|
@@ -2203,7 +2214,10 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
2203
2214
|
);
|
|
2204
2215
|
if (existing2.toArray().length > 0) {
|
|
2205
2216
|
const fields = schema.uniqueOn.map((f) => `${f}=${finalData[f] ?? "null"}`).join(", ");
|
|
2206
|
-
return {
|
|
2217
|
+
return {
|
|
2218
|
+
success: false,
|
|
2219
|
+
error: `Duplicate: a record with ${fields} already exists in ${collection}`
|
|
2220
|
+
};
|
|
2207
2221
|
}
|
|
2208
2222
|
}
|
|
2209
2223
|
if (isUpdate) {
|
|
@@ -2217,13 +2231,16 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
2217
2231
|
ctx.sql.exec(`UPDATE "${tbl}" SET ${setClauses.join(", ")} WHERE _row_id = ?`, ...params);
|
|
2218
2232
|
} else {
|
|
2219
2233
|
const colIds = Object.keys(colValues);
|
|
2220
|
-
const allCols = [
|
|
2234
|
+
const allCols = [
|
|
2235
|
+
"_row_id",
|
|
2236
|
+
"_created_by",
|
|
2237
|
+
"_created_at",
|
|
2238
|
+
"_updated_at",
|
|
2239
|
+
...colIds.map((c) => `"${c}"`)
|
|
2240
|
+
];
|
|
2221
2241
|
const placeholders = allCols.map(() => "?").join(", ");
|
|
2222
2242
|
const params = [recordId, userId, now, now, ...colIds.map((c) => colValues[c])];
|
|
2223
|
-
ctx.sql.exec(
|
|
2224
|
-
`INSERT INTO "${tbl}" (${allCols.join(", ")}) VALUES (${placeholders})`,
|
|
2225
|
-
...params
|
|
2226
|
-
);
|
|
2243
|
+
ctx.sql.exec(`INSERT INTO "${tbl}" (${allCols.join(", ")}) VALUES (${placeholders})`, ...params);
|
|
2227
2244
|
}
|
|
2228
2245
|
const saved = getRecord(ctx.sql, collection, recordId, schema);
|
|
2229
2246
|
const record = {
|
|
@@ -3456,9 +3473,21 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3456
3473
|
ownerUserId;
|
|
3457
3474
|
/** True until the first fetch() completes — detects hibernation wake-up */
|
|
3458
3475
|
freshConstruct = true;
|
|
3476
|
+
/**
|
|
3477
|
+
* Per-connection `[DO Perf]` timing logs are noisy on every hot path, so
|
|
3478
|
+
* they're gated behind a `DEEPSPACE_DO_PERF` env binding (set it to any
|
|
3479
|
+
* truthy value on the worker to opt in). Off by default.
|
|
3480
|
+
*/
|
|
3481
|
+
get perfLogEnabled() {
|
|
3482
|
+
return !!this.env?.DEEPSPACE_DO_PERF;
|
|
3483
|
+
}
|
|
3459
3484
|
constructor(state, env, schemas = [], config = {}) {
|
|
3460
3485
|
super(state, env);
|
|
3461
|
-
this.schemaRegistry = new SchemaRegistry([
|
|
3486
|
+
this.schemaRegistry = new SchemaRegistry([
|
|
3487
|
+
...SYSTEM_COLLECTION_SCHEMAS,
|
|
3488
|
+
BASE_USERS_SCHEMA,
|
|
3489
|
+
...schemas
|
|
3490
|
+
]);
|
|
3462
3491
|
this.ownerUserId = config.ownerUserId ?? null;
|
|
3463
3492
|
const wsCount = this.state.getWebSockets().length;
|
|
3464
3493
|
if (wsCount > 0) {
|
|
@@ -3542,10 +3571,7 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3542
3571
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3543
3572
|
for (const row of oldUsers) {
|
|
3544
3573
|
const r = row;
|
|
3545
|
-
const existing = this.sql.exec(
|
|
3546
|
-
`SELECT 1 FROM c_users WHERE _row_id = ?`,
|
|
3547
|
-
r.user_id
|
|
3548
|
-
).toArray();
|
|
3574
|
+
const existing = this.sql.exec(`SELECT 1 FROM c_users WHERE _row_id = ?`, r.user_id).toArray();
|
|
3549
3575
|
if (existing.length > 0) continue;
|
|
3550
3576
|
this.sql.exec(
|
|
3551
3577
|
`INSERT INTO c_users (_row_id, _created_by, _created_at, _updated_at, col_email, col_name, col_imageurl, col_role, col_createdat, col_lastseenat) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -3579,7 +3605,6 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3579
3605
|
}
|
|
3580
3606
|
let migrated = 0;
|
|
3581
3607
|
let skipped = 0;
|
|
3582
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3583
3608
|
for (const row of rows) {
|
|
3584
3609
|
const r = row;
|
|
3585
3610
|
const schema = this.schemaRegistry.get(r.collection);
|
|
@@ -3588,17 +3613,11 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3588
3613
|
continue;
|
|
3589
3614
|
}
|
|
3590
3615
|
const tbl = collectionTableName(r.collection);
|
|
3591
|
-
const tblExists = this.sql.exec(
|
|
3592
|
-
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
|
3593
|
-
tbl
|
|
3594
|
-
).toArray().length > 0;
|
|
3616
|
+
const tblExists = this.sql.exec(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, tbl).toArray().length > 0;
|
|
3595
3617
|
if (!tblExists) {
|
|
3596
3618
|
this.ensureCollectionTable(schema);
|
|
3597
3619
|
}
|
|
3598
|
-
const existing = this.sql.exec(
|
|
3599
|
-
`SELECT 1 FROM "${tbl}" WHERE _row_id = ?`,
|
|
3600
|
-
r.record_id
|
|
3601
|
-
).toArray();
|
|
3620
|
+
const existing = this.sql.exec(`SELECT 1 FROM "${tbl}" WHERE _row_id = ?`, r.record_id).toArray();
|
|
3602
3621
|
if (existing.length > 0) {
|
|
3603
3622
|
skipped++;
|
|
3604
3623
|
continue;
|
|
@@ -3613,9 +3632,21 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3613
3632
|
const columns = schema.columns.map(resolveColumn);
|
|
3614
3633
|
const colValues = dataToColumnValues(data, columns);
|
|
3615
3634
|
const colIds = Object.keys(colValues);
|
|
3616
|
-
const allCols = [
|
|
3635
|
+
const allCols = [
|
|
3636
|
+
"_row_id",
|
|
3637
|
+
"_created_by",
|
|
3638
|
+
"_created_at",
|
|
3639
|
+
"_updated_at",
|
|
3640
|
+
...colIds.map((c) => `"${c}"`)
|
|
3641
|
+
];
|
|
3617
3642
|
const placeholders = allCols.map(() => "?").join(", ");
|
|
3618
|
-
const params = [
|
|
3643
|
+
const params = [
|
|
3644
|
+
r.record_id,
|
|
3645
|
+
r.created_by,
|
|
3646
|
+
r.created_at,
|
|
3647
|
+
r.updated_at,
|
|
3648
|
+
...colIds.map((c) => colValues[c])
|
|
3649
|
+
];
|
|
3619
3650
|
this.sql.exec(
|
|
3620
3651
|
`INSERT INTO "${tbl}" (${allCols.join(", ")}) VALUES (${placeholders})`,
|
|
3621
3652
|
...params
|
|
@@ -3623,7 +3654,9 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3623
3654
|
migrated++;
|
|
3624
3655
|
}
|
|
3625
3656
|
if (migrated > 0 || skipped > 0) {
|
|
3626
|
-
console.log(
|
|
3657
|
+
console.log(
|
|
3658
|
+
`[RecordRoom] Migrated ${migrated} records from document-mode, ${skipped} skipped`
|
|
3659
|
+
);
|
|
3627
3660
|
}
|
|
3628
3661
|
this.sql.exec(`DROP TABLE IF EXISTS records`);
|
|
3629
3662
|
} catch (error) {
|
|
@@ -3646,7 +3679,12 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3646
3679
|
// ============================================================================
|
|
3647
3680
|
async onConnect(ws, user) {
|
|
3648
3681
|
await this.ensureInitialized();
|
|
3649
|
-
const timing = this._fetchTiming ?? {
|
|
3682
|
+
const timing = this._fetchTiming ?? {
|
|
3683
|
+
fetchStart: Date.now(),
|
|
3684
|
+
isColdStart: false,
|
|
3685
|
+
needsInit: false,
|
|
3686
|
+
initMs: 0
|
|
3687
|
+
};
|
|
3650
3688
|
const userId = user.userId;
|
|
3651
3689
|
const userName = user.userName;
|
|
3652
3690
|
const userEmail = user.userEmail;
|
|
@@ -3657,7 +3695,16 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3657
3695
|
const isOwner2 = this.ownerUserId != null && userId === this.ownerUserId;
|
|
3658
3696
|
const regStart = Date.now();
|
|
3659
3697
|
const defaultRole = this.schemaRegistry.get("users")?.defaultRole ?? "member";
|
|
3660
|
-
const registeredUser = await registerUser(
|
|
3698
|
+
const registeredUser = await registerUser(
|
|
3699
|
+
this.sql,
|
|
3700
|
+
userId,
|
|
3701
|
+
userName,
|
|
3702
|
+
userEmail,
|
|
3703
|
+
userImageUrl,
|
|
3704
|
+
isOwner2,
|
|
3705
|
+
defaultRole,
|
|
3706
|
+
this.schemaRegistry
|
|
3707
|
+
);
|
|
3661
3708
|
const regMs = Date.now() - regStart;
|
|
3662
3709
|
attachment = {
|
|
3663
3710
|
userId: registeredUser.id,
|
|
@@ -3671,7 +3718,10 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3671
3718
|
};
|
|
3672
3719
|
this.send(ws, { type: MSG.USER_INFO, payload: registeredUser });
|
|
3673
3720
|
const totalMs = Date.now() - timing.fetchStart;
|
|
3674
|
-
|
|
3721
|
+
if (this.perfLogEnabled)
|
|
3722
|
+
console.log(
|
|
3723
|
+
`[DO Perf] cold=${timing.isColdStart} | init: ${timing.initMs}ms reg: ${regMs}ms | total: ${totalMs}ms`
|
|
3724
|
+
);
|
|
3675
3725
|
} else {
|
|
3676
3726
|
attachment = {
|
|
3677
3727
|
userId,
|
|
@@ -3682,63 +3732,37 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3682
3732
|
yjsSubscriptions: [],
|
|
3683
3733
|
yjsClientId: this.nextYjsClientId++
|
|
3684
3734
|
};
|
|
3685
|
-
this.send(ws, {
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3735
|
+
this.send(ws, {
|
|
3736
|
+
type: MSG.USER_INFO,
|
|
3737
|
+
payload: {
|
|
3738
|
+
id: userId,
|
|
3739
|
+
name: "Anonymous",
|
|
3740
|
+
email: "",
|
|
3741
|
+
role: ROLE_ANONYMOUS,
|
|
3742
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3743
|
+
lastSeenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3744
|
+
}
|
|
3745
|
+
});
|
|
3693
3746
|
const totalMs = Date.now() - timing.fetchStart;
|
|
3694
|
-
|
|
3747
|
+
if (this.perfLogEnabled)
|
|
3748
|
+
console.log(`[DO Perf] cold=${timing.isColdStart} anon | total: ${totalMs}ms`);
|
|
3695
3749
|
}
|
|
3696
3750
|
this._fetchTiming = null;
|
|
3697
3751
|
return attachment;
|
|
3698
3752
|
}
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
await this.handleRecordMessage(ws, attachment, msg);
|
|
3708
|
-
} catch (e) {
|
|
3709
|
-
const errMsg = e instanceof Error ? e.message : String(e);
|
|
3710
|
-
console.error(`[RecordRoom] Message handler error: ${errMsg}`);
|
|
3711
|
-
this.send(ws, { type: MSG.ERROR, payload: { error: `Invalid message: ${errMsg}` } });
|
|
3712
|
-
}
|
|
3713
|
-
}
|
|
3714
|
-
async onBinaryMessage(ws, user, data) {
|
|
3715
|
-
await this.ensureInitialized();
|
|
3716
|
-
const attachment = ws.deserializeAttachment();
|
|
3717
|
-
if (!attachment) return;
|
|
3718
|
-
try {
|
|
3719
|
-
await handleYjsBinaryMessage(
|
|
3720
|
-
this.createYjsContext(),
|
|
3721
|
-
ws,
|
|
3722
|
-
attachment,
|
|
3723
|
-
new Uint8Array(data)
|
|
3724
|
-
);
|
|
3725
|
-
} catch (e) {
|
|
3726
|
-
console.error("[RecordRoom] Yjs binary message error:", e);
|
|
3727
|
-
}
|
|
3728
|
-
}
|
|
3729
|
-
onDisconnect(ws, user) {
|
|
3730
|
-
console.log(`[RecordRoom] webSocketClose`);
|
|
3731
|
-
try {
|
|
3732
|
-
const attachment = ws.deserializeAttachment();
|
|
3733
|
-
if (attachment) {
|
|
3734
|
-
broadcastAwarenessRemoval(this.createYjsContext(), attachment);
|
|
3735
|
-
}
|
|
3736
|
-
} catch {
|
|
3737
|
-
}
|
|
3753
|
+
/**
|
|
3754
|
+
* Required to satisfy BaseRoom's abstract contract, but never invoked:
|
|
3755
|
+
* RecordRoom overrides `webSocketMessage`/`webSocketClose` directly (below),
|
|
3756
|
+
* so the BaseRoom dispatch path that would call this never runs. All real
|
|
3757
|
+
* message handling lives in `handleRecordMessage`.
|
|
3758
|
+
*/
|
|
3759
|
+
onMessage() {
|
|
3760
|
+
throw new Error("RecordRoom.onMessage is unreachable; use webSocketMessage");
|
|
3738
3761
|
}
|
|
3739
3762
|
// ============================================================================
|
|
3740
|
-
// Hibernation API
|
|
3741
|
-
//
|
|
3763
|
+
// Hibernation API — RecordRoom overrides these directly (rather than using
|
|
3764
|
+
// BaseRoom's onMessage/onBinaryMessage/onDisconnect hooks) so it can run
|
|
3765
|
+
// ensureInitialized() before every message after a hibernation wake-up.
|
|
3742
3766
|
// ============================================================================
|
|
3743
3767
|
async webSocketMessage(ws, message) {
|
|
3744
3768
|
await this.ensureInitialized();
|
|
@@ -3809,7 +3833,12 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3809
3833
|
handleUserList(userCtx, ws, attachment);
|
|
3810
3834
|
break;
|
|
3811
3835
|
case MSG.USER_UPDATE:
|
|
3812
|
-
handleUserUpdate(
|
|
3836
|
+
handleUserUpdate(
|
|
3837
|
+
recordCtx,
|
|
3838
|
+
ws,
|
|
3839
|
+
attachment,
|
|
3840
|
+
payload
|
|
3841
|
+
);
|
|
3813
3842
|
break;
|
|
3814
3843
|
case MSG.SET_ROLE:
|
|
3815
3844
|
await handleSetRole(userCtx, ws, attachment, payload);
|
|
@@ -3975,7 +4004,7 @@ var YjsRoom = class extends BaseRoom {
|
|
|
3975
4004
|
this.sendAwarenessSnapshot(ws);
|
|
3976
4005
|
return attachment;
|
|
3977
4006
|
}
|
|
3978
|
-
onMessage(
|
|
4007
|
+
onMessage(_ws, _user, _message) {
|
|
3979
4008
|
}
|
|
3980
4009
|
onBinaryMessage(ws, user, data) {
|
|
3981
4010
|
const bytes = new Uint8Array(data);
|
|
@@ -3987,7 +4016,7 @@ var YjsRoom = class extends BaseRoom {
|
|
|
3987
4016
|
this.handleAwareness(ws, decoder, bytes);
|
|
3988
4017
|
}
|
|
3989
4018
|
}
|
|
3990
|
-
onDisconnect(ws,
|
|
4019
|
+
onDisconnect(ws, _user) {
|
|
3991
4020
|
const attachment = ws.deserializeAttachment();
|
|
3992
4021
|
if (attachment?.awarenessClientId == null) return;
|
|
3993
4022
|
const clientId = attachment.awarenessClientId;
|
|
@@ -4348,16 +4377,16 @@ var GameRoom = class extends BaseRoom {
|
|
|
4348
4377
|
return this.currentTick;
|
|
4349
4378
|
}
|
|
4350
4379
|
/** Called when a player connects */
|
|
4351
|
-
onPlayerJoin(
|
|
4380
|
+
onPlayerJoin(_player) {
|
|
4352
4381
|
}
|
|
4353
4382
|
/** Called when a player disconnects */
|
|
4354
|
-
onPlayerLeave(
|
|
4383
|
+
onPlayerLeave(_player) {
|
|
4355
4384
|
}
|
|
4356
4385
|
/** Called when the game starts */
|
|
4357
4386
|
onGameStart() {
|
|
4358
4387
|
}
|
|
4359
4388
|
/** Called when the game ends */
|
|
4360
|
-
onGameEnd(
|
|
4389
|
+
onGameEnd(_finalState) {
|
|
4361
4390
|
}
|
|
4362
4391
|
/**
|
|
4363
4392
|
* Called once when the DO first hydrates persisted state from storage.
|
|
@@ -6817,6 +6846,18 @@ async function timingSafeEqualHex(a, b) {
|
|
|
6817
6846
|
return diff === 0;
|
|
6818
6847
|
}
|
|
6819
6848
|
|
|
6849
|
+
// src/server/auth/testAccounts.ts
|
|
6850
|
+
var TEST_ACCOUNT_EMAIL_SUFFIX = "@deepspace.test";
|
|
6851
|
+
function isTestAccountEmail(email) {
|
|
6852
|
+
return !!email && email.trim().toLowerCase().endsWith(TEST_ACCOUNT_EMAIL_SUFFIX);
|
|
6853
|
+
}
|
|
6854
|
+
function isTestAccountClaims(claims) {
|
|
6855
|
+
return claims?.isTestAccount === true;
|
|
6856
|
+
}
|
|
6857
|
+
function isTestAccountTier(tier) {
|
|
6858
|
+
return tier === "test";
|
|
6859
|
+
}
|
|
6860
|
+
|
|
6820
6861
|
// src/server/auth/betterAuth.ts
|
|
6821
6862
|
import { betterAuth } from "better-auth";
|
|
6822
6863
|
import { organization, twoFactor } from "better-auth/plugins";
|
|
@@ -6904,11 +6945,8 @@ function isEntitled(tier, status) {
|
|
|
6904
6945
|
|
|
6905
6946
|
// src/server/subscription.ts
|
|
6906
6947
|
function appIdentityHeaders(c, extra) {
|
|
6907
|
-
const h = new Headers({
|
|
6908
|
-
|
|
6909
|
-
"x-app-name": c.env.APP_NAME,
|
|
6910
|
-
...extra ?? {}
|
|
6911
|
-
});
|
|
6948
|
+
const h = new Headers(extra ?? {});
|
|
6949
|
+
appendAppIdentity(h, c.env);
|
|
6912
6950
|
const authz = c.req.header("authorization");
|
|
6913
6951
|
if (authz) h.set("authorization", authz);
|
|
6914
6952
|
return h;
|
|
@@ -7006,12 +7044,9 @@ var CancelSubscriptionError = class extends Error {
|
|
|
7006
7044
|
async function refundInvoice(c, opts) {
|
|
7007
7045
|
const authz = c.req.header("authorization");
|
|
7008
7046
|
const nonce = opts.requestNonce ?? crypto.randomUUID();
|
|
7009
|
-
const headers = {
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
"x-app-name": c.env.APP_NAME
|
|
7013
|
-
};
|
|
7014
|
-
if (authz) headers["authorization"] = authz;
|
|
7047
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
7048
|
+
appendAppIdentity(headers, c.env);
|
|
7049
|
+
if (authz) headers.set("authorization", authz);
|
|
7015
7050
|
const res = await apiWorkerFetch(c.env, "/api/refunds/create", {
|
|
7016
7051
|
method: "POST",
|
|
7017
7052
|
headers,
|
|
@@ -7075,6 +7110,7 @@ export {
|
|
|
7075
7110
|
SchemaRegistry,
|
|
7076
7111
|
SubscriptionAuthError,
|
|
7077
7112
|
SubscriptionRequiredError,
|
|
7113
|
+
TEST_ACCOUNT_EMAIL_SUFFIX,
|
|
7078
7114
|
USERS_COLUMNS,
|
|
7079
7115
|
VOTING_SCHEMAS,
|
|
7080
7116
|
WORKSPACE_SCHEMAS,
|
|
@@ -7139,6 +7175,9 @@ export {
|
|
|
7139
7175
|
handleYjsLeave,
|
|
7140
7176
|
isAutoProvision,
|
|
7141
7177
|
isOwner,
|
|
7178
|
+
isTestAccountClaims,
|
|
7179
|
+
isTestAccountEmail,
|
|
7180
|
+
isTestAccountTier,
|
|
7142
7181
|
lintSchema,
|
|
7143
7182
|
loadMessages,
|
|
7144
7183
|
makeDefaultSummarizer,
|