@awiki/dsh-plugin 0.3.10 → 0.3.11-rc.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.
Files changed (81) hide show
  1. package/README.md +4 -3
  2. package/README.zh.md +4 -3
  3. package/lib/client.js +1351 -158
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +172 -93
  6. package/lib/model-proxy-contract.js +8 -8
  7. package/lib/typert.host.js +56 -56
  8. package/lib/typert.remote-client.js +56 -56
  9. package/lib/types/client/AwikiIdentityAccess.d.ts +6 -4
  10. package/lib/types/client/AwikiIdentityAccess.d.ts.map +1 -1
  11. package/lib/types/client/AwikiIdentityAccess.js +111 -43
  12. package/lib/types/client/AwikiIdentityAccess.js.map +1 -1
  13. package/lib/types/client/AwikiOverlay.js +1 -1
  14. package/lib/types/client/AwikiOverlay.js.map +1 -1
  15. package/lib/types/client/AwikiRecoveryForm.d.ts +1 -0
  16. package/lib/types/client/AwikiRecoveryForm.d.ts.map +1 -1
  17. package/lib/types/client/AwikiRecoveryForm.js +3 -2
  18. package/lib/types/client/AwikiRecoveryForm.js.map +1 -1
  19. package/lib/types/client/AwikiSettingsSection.d.ts +1 -1
  20. package/lib/types/client/AwikiSettingsSection.d.ts.map +1 -1
  21. package/lib/types/client/awiki-client-bridge.d.ts +1 -1
  22. package/lib/types/client/awiki-client-bridge.d.ts.map +1 -1
  23. package/lib/types/client/awiki-client-bridge.js +1 -1
  24. package/lib/types/client/awiki-client-bridge.js.map +1 -1
  25. package/lib/types/client/controller.d.ts +8 -0
  26. package/lib/types/client/controller.d.ts.map +1 -1
  27. package/lib/types/client/controller.js +274 -53
  28. package/lib/types/client/controller.js.map +1 -1
  29. package/lib/types/client/index.d.ts +1 -1
  30. package/lib/types/client/index.d.ts.map +1 -1
  31. package/lib/types/client/index.js +2 -1
  32. package/lib/types/client/index.js.map +1 -1
  33. package/lib/types/client/otp-cooldown.d.ts +1 -0
  34. package/lib/types/client/otp-cooldown.d.ts.map +1 -1
  35. package/lib/types/client/otp-cooldown.js +12 -1
  36. package/lib/types/client/otp-cooldown.js.map +1 -1
  37. package/lib/types/client/settings-controller.d.ts +4 -2
  38. package/lib/types/client/settings-controller.d.ts.map +1 -1
  39. package/lib/types/client/settings-controller.js +24 -8
  40. package/lib/types/client/settings-controller.js.map +1 -1
  41. package/lib/types/client/slots.d.ts +1 -0
  42. package/lib/types/client/slots.d.ts.map +1 -1
  43. package/lib/types/client/store.d.ts +1 -1
  44. package/lib/types/client/store.d.ts.map +1 -1
  45. package/lib/types/client/store.js +1 -1
  46. package/lib/types/client/store.js.map +1 -1
  47. package/lib/types/index.d.ts +1 -0
  48. package/lib/types/index.d.ts.map +1 -1
  49. package/lib/types/index.js +35 -9
  50. package/lib/types/index.js.map +1 -1
  51. package/lib/types/listener.d.ts.map +1 -1
  52. package/lib/types/listener.js +2 -1
  53. package/lib/types/listener.js.map +1 -1
  54. package/lib/types/model-proxy-contract.d.ts +8 -8
  55. package/lib/types/model-proxy-contract.d.ts.map +1 -1
  56. package/lib/types/model-proxy-contract.js +8 -8
  57. package/lib/types/model-proxy-contract.js.map +1 -1
  58. package/lib/types/package-version.generated.d.ts +2 -2
  59. package/lib/types/package-version.generated.d.ts.map +1 -1
  60. package/lib/types/package-version.generated.js +2 -2
  61. package/lib/types/package-version.generated.js.map +1 -1
  62. package/lib/types/registration-policy.d.ts +7 -0
  63. package/lib/types/registration-policy.d.ts.map +1 -0
  64. package/lib/types/registration-policy.js +21 -0
  65. package/lib/types/registration-policy.js.map +1 -0
  66. package/lib/types/settings-rpc-contract.d.ts +14 -14
  67. package/lib/types/settings-rpc-contract.d.ts.map +1 -1
  68. package/lib/types/settings-rpc-contract.js +14 -14
  69. package/lib/types/settings-rpc-contract.js.map +1 -1
  70. package/lib/types/settings-rpc.d.ts.map +1 -1
  71. package/lib/types/settings-rpc.js +2 -2
  72. package/lib/types/settings-rpc.js.map +1 -1
  73. package/lib/types/settings-transport.d.ts +7 -0
  74. package/lib/types/settings-transport.d.ts.map +1 -0
  75. package/lib/types/settings-transport.js +52 -0
  76. package/lib/types/settings-transport.js.map +1 -0
  77. package/lib/types/types.d.ts +1 -1
  78. package/lib/types/types.d.ts.map +1 -1
  79. package/lib/types/update-policy.d.ts +2 -2
  80. package/lib/types/update-policy.d.ts.map +1 -1
  81. package/package.json +82 -73
package/lib/index.js CHANGED
@@ -5,15 +5,151 @@ import { homedir } from "node:os";
5
5
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
6
6
  import z from "@deepseek-ai/schemastery";
7
7
  import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
8
- import { SettingsConflictError, settingsNamespace } from "@deepseek-ai/dsh-settings";
8
+ import { SettingsConflictError } from "@deepseek-ai/dsh-settings";
9
9
  import { chmod, lstat, mkdir, readFile, readdir, rename, rm, unlink, utimes, writeFile } from "node:fs/promises";
10
10
  import { defineTool } from "@deepseek-ai/dsh-tools";
11
+ import { SessionId, SessionLogOffset } from "@deepseek-ai/dsh-session";
11
12
  import { installModelSelection } from "@deepseek-ai/dsh-agent";
12
13
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
13
- import { SessionId } from "@deepseek-ai/dsh-session";
14
14
  import { fileURLToPath } from "node:url";
15
15
  import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
16
16
  import { satisfies } from "semver";
17
+ //#region lib/types/builtin-tenant-config.js
18
+ /** Build-injected two-slot tenant catalog with a source-tree default for tests. */
19
+ function record(value) {
20
+ return typeof value === "object" && value !== null && !Array.isArray(value);
21
+ }
22
+ function definition(value) {
23
+ if (!record(value) || !record(value.display_name) || typeof value.display_name["zh-CN"] !== "string" || value.display_name["zh-CN"].trim() === "" || typeof value.display_name.en !== "string" || value.display_name.en.trim() === "" || typeof value.backend_origin !== "string" || typeof value.did_host !== "string") throw new Error("awiki: invalid built-in tenant definition");
24
+ const origin = new URL(value.backend_origin);
25
+ const loopback = origin.protocol === "http:" && [
26
+ "localhost",
27
+ "127.0.0.1",
28
+ "[::1]"
29
+ ].includes(origin.hostname);
30
+ if (origin.protocol !== "https:" && !loopback || origin.username !== "" || origin.password !== "" || origin.pathname !== "/" || origin.search !== "" || origin.hash !== "" || !loopback && origin.port !== "") throw new Error("awiki: built-in tenant origin must be an HTTPS origin");
31
+ const didHost = value.did_host.trim().toLowerCase().replace(/\.$/u, "");
32
+ if (origin.hostname !== didHost) throw new Error("awiki: built-in tenant DID host must match its origin");
33
+ return {
34
+ displayName: {
35
+ "zh-CN": value.display_name["zh-CN"].trim(),
36
+ en: value.display_name.en.trim()
37
+ },
38
+ backendOrigin: origin.origin,
39
+ didHost
40
+ };
41
+ }
42
+ function decodeBuiltinTenantConfig(value) {
43
+ if (!record(value) || value.schema_version !== 1 || value.default_slot !== "primary" && value.default_slot !== "secondary" || !record(value.tenants) || Object.keys(value.tenants).sort().join(",") !== "primary,secondary") throw new Error("awiki: invalid built-in tenant config");
44
+ const primary = definition(value.tenants.primary);
45
+ const secondary = definition(value.tenants.secondary);
46
+ if (primary.backendOrigin === secondary.backendOrigin || primary.didHost === secondary.didHost) throw new Error("awiki: built-in tenant slots must use distinct endpoints");
47
+ return {
48
+ schemaVersion: 1,
49
+ defaultSlot: value.default_slot,
50
+ tenants: {
51
+ primary,
52
+ secondary
53
+ }
54
+ };
55
+ }
56
+ function rawConfig() {
57
+ return JSON.parse("{\n \"schema_version\": 1,\n \"default_slot\": \"primary\",\n \"tenants\": {\n \"primary\": {\n \"display_name\": {\n \"zh-CN\": \"AWiki 中国(上海)\",\n \"en\": \"AWiki China (Shanghai)\"\n },\n \"backend_origin\": \"https://awiki.me\",\n \"did_host\": \"awiki.me\"\n },\n \"secondary\": {\n \"display_name\": {\n \"zh-CN\": \"AWiki 全球(硅谷)\",\n \"en\": \"AWiki Global (Silicon Valley)\"\n },\n \"backend_origin\": \"https://awiki.ai\",\n \"did_host\": \"awiki.ai\"\n }\n }\n}\n");
58
+ }
59
+ const AWIKI_BUILTIN_TENANT_CONFIG = decodeBuiltinTenantConfig(rawConfig());
60
+ const AWIKI_DEFAULT_BUILTIN_TENANT = AWIKI_BUILTIN_TENANT_CONFIG.tenants[AWIKI_BUILTIN_TENANT_CONFIG.defaultSlot];
61
+ //#endregion
62
+ //#region lib/types/domain.js
63
+ /** Client-safe AWiki Handle provider domain constants and validation. */
64
+ /** Default Handle provider domain for new AWiki deployments. */
65
+ const DEFAULT_AWIKI_DOMAIN = AWIKI_DEFAULT_BUILTIN_TENANT.didHost;
66
+ /** Field carrying the Handle provider domain in the AWiki settings namespace. */
67
+ const AWIKI_DOMAIN_FIELD = "domain";
68
+ /** Settings namespace owned by the AWiki plugin. */
69
+ const AWIKI_SETTINGS_NAMESPACE = "awiki";
70
+ /** Normalize and validate one DNS provider domain. */
71
+ function normalizeAwikiDomain(raw, field = "domain") {
72
+ const value = raw.trim().toLowerCase();
73
+ const valid = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(value);
74
+ if (value.length > 253 || !valid) throw new TypeError(`awiki: ${field} must contain a valid DNS domain`);
75
+ return value;
76
+ }
77
+ //#endregion
78
+ //#region lib/types/settings-rpc-contract.js
79
+ /** Shared Connection carrier with plugin-owned exact loopback routes. */
80
+ const AWIKI_SETTINGS_RPC_CHANNEL = "/api";
81
+ /** Supported channel-relative operations. */
82
+ const AWIKI_SETTINGS_RPC_ENDPOINTS = {
83
+ describe: "awiki-settings/describe",
84
+ setDomain: "awiki-settings/set-domain",
85
+ resetDomain: "awiki-settings/reset-domain",
86
+ describeTenants: "awiki-settings/describe-tenants",
87
+ createTenant: "awiki-settings/create-tenant",
88
+ renameTenant: "awiki-settings/rename-tenant",
89
+ switchTenant: "awiki-settings/switch-tenant",
90
+ archiveTenant: "awiki-settings/archive-tenant",
91
+ describeUpdatePolicy: "awiki-settings/describe-update-policy",
92
+ refreshUpdatePolicy: "awiki-settings/refresh-update-policy",
93
+ describeDesktopUpdate: "awiki-settings/describe-desktop-update",
94
+ refreshDesktopUpdate: "awiki-settings/refresh-desktop-update"
95
+ };
96
+ //#endregion
97
+ //#region lib/types/settings-transport.js
98
+ /** Register exact buffered routes; Connection applies authentication before dispatch. */
99
+ function registerAwikiSettingsTransport(connection, handler) {
100
+ registerAwikiLoopbackRpc(connection, AWIKI_SETTINGS_RPC_CHANNEL, Object.values(AWIKI_SETTINGS_RPC_ENDPOINTS), handler);
101
+ }
102
+ /** Shared carrier for the AWiki and Model Proxy plugin-owned local operations. */
103
+ function registerAwikiLoopbackRpc(connection, channel, endpoints, handler) {
104
+ for (const endpoint of endpoints) connection.fetch.register({
105
+ path: `${channel}/${endpoint}`,
106
+ methods: ["POST"],
107
+ requestBody: "buffered",
108
+ async fetch(request) {
109
+ const authority = request.headers.get("host") ?? "";
110
+ if (!/^(?:localhost|127\.0\.0\.1|\[::1\])(?::[0-9]{1,5})?$/iu.test(authority)) return new Response("forbidden", { status: 403 });
111
+ if (request.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") return new Response("unsupported content type", { status: 415 });
112
+ let body;
113
+ try {
114
+ body = await request.json();
115
+ } catch {
116
+ return new Response("invalid request", { status: 400 });
117
+ }
118
+ if (typeof body !== "object" || body === null || Array.isArray(body)) return new Response("invalid request", { status: 400 });
119
+ const envelope = body;
120
+ if (Object.keys(envelope).sort().join(",") !== "method,payload,rpcId,type" || envelope.type !== "client-request" || envelope.method !== endpoint || typeof envelope.rpcId !== "string" || envelope.rpcId.length === 0 || envelope.rpcId.length > 256) return new Response("invalid request", { status: 400 });
121
+ try {
122
+ const result = await handler(endpoint, envelope.payload, request.signal);
123
+ return Response.json({
124
+ type: "server-response",
125
+ rpcId: envelope.rpcId,
126
+ result
127
+ });
128
+ } catch {
129
+ return new Response("AWiki settings unavailable", { status: 500 });
130
+ }
131
+ }
132
+ });
133
+ }
134
+ //#endregion
135
+ //#region lib/types/registration-policy.js
136
+ const HANDLE_LOCAL_PART = /^(?!-)(?!.*--)[a-z0-9-]{1,63}(?<!-)$/u;
137
+ /** Return the canonical local part when the input has valid WNS local-part syntax. */
138
+ function registrationHandleLocalPart(value) {
139
+ let normalized = value.trim().toLowerCase();
140
+ if (normalized.startsWith("wba://")) normalized = normalized.slice(6);
141
+ const dot = normalized.indexOf(".");
142
+ const localPart = (dot < 0 ? normalized : normalized.slice(0, dot)).trim();
143
+ return HANDLE_LOCAL_PART.test(localPart) ? localPart : void 0;
144
+ }
145
+ /** One- through four-character Handle registrations require the unavailable invitation flow. */
146
+ function shortHandleInviteRequired(value) {
147
+ const localPart = registrationHandleLocalPart(value);
148
+ if (localPart === void 0) return false;
149
+ const length = Array.from(localPart).length;
150
+ return length >= 1 && length <= 4;
151
+ }
152
+ //#endregion
17
153
  //#region lib/types/version.js
18
154
  /** Shared strict version comparison for update presentation and Host gates. */
19
155
  function assertVersion(value) {
@@ -1151,67 +1287,6 @@ function mailSendRequest(request) {
1151
1287
  };
1152
1288
  }
1153
1289
  //#endregion
1154
- //#region lib/types/builtin-tenant-config.js
1155
- /** Build-injected two-slot tenant catalog with a source-tree default for tests. */
1156
- function record(value) {
1157
- return typeof value === "object" && value !== null && !Array.isArray(value);
1158
- }
1159
- function definition(value) {
1160
- if (!record(value) || !record(value.display_name) || typeof value.display_name["zh-CN"] !== "string" || value.display_name["zh-CN"].trim() === "" || typeof value.display_name.en !== "string" || value.display_name.en.trim() === "" || typeof value.backend_origin !== "string" || typeof value.did_host !== "string") throw new Error("awiki: invalid built-in tenant definition");
1161
- const origin = new URL(value.backend_origin);
1162
- const loopback = origin.protocol === "http:" && [
1163
- "localhost",
1164
- "127.0.0.1",
1165
- "[::1]"
1166
- ].includes(origin.hostname);
1167
- if (origin.protocol !== "https:" && !loopback || origin.username !== "" || origin.password !== "" || origin.pathname !== "/" || origin.search !== "" || origin.hash !== "" || !loopback && origin.port !== "") throw new Error("awiki: built-in tenant origin must be an HTTPS origin");
1168
- const didHost = value.did_host.trim().toLowerCase().replace(/\.$/u, "");
1169
- if (origin.hostname !== didHost) throw new Error("awiki: built-in tenant DID host must match its origin");
1170
- return {
1171
- displayName: {
1172
- "zh-CN": value.display_name["zh-CN"].trim(),
1173
- en: value.display_name.en.trim()
1174
- },
1175
- backendOrigin: origin.origin,
1176
- didHost
1177
- };
1178
- }
1179
- function decodeBuiltinTenantConfig(value) {
1180
- if (!record(value) || value.schema_version !== 1 || value.default_slot !== "primary" && value.default_slot !== "secondary" || !record(value.tenants) || Object.keys(value.tenants).sort().join(",") !== "primary,secondary") throw new Error("awiki: invalid built-in tenant config");
1181
- const primary = definition(value.tenants.primary);
1182
- const secondary = definition(value.tenants.secondary);
1183
- if (primary.backendOrigin === secondary.backendOrigin || primary.didHost === secondary.didHost) throw new Error("awiki: built-in tenant slots must use distinct endpoints");
1184
- return {
1185
- schemaVersion: 1,
1186
- defaultSlot: value.default_slot,
1187
- tenants: {
1188
- primary,
1189
- secondary
1190
- }
1191
- };
1192
- }
1193
- function rawConfig() {
1194
- return JSON.parse("{\n \"schema_version\": 1,\n \"default_slot\": \"primary\",\n \"tenants\": {\n \"primary\": {\n \"display_name\": {\n \"zh-CN\": \"AWiki 中国(上海)\",\n \"en\": \"AWiki China (Shanghai)\"\n },\n \"backend_origin\": \"https://awiki.me\",\n \"did_host\": \"awiki.me\"\n },\n \"secondary\": {\n \"display_name\": {\n \"zh-CN\": \"AWiki 全球(硅谷)\",\n \"en\": \"AWiki Global (Silicon Valley)\"\n },\n \"backend_origin\": \"https://awiki.ai\",\n \"did_host\": \"awiki.ai\"\n }\n }\n}\n");
1195
- }
1196
- const AWIKI_BUILTIN_TENANT_CONFIG = decodeBuiltinTenantConfig(rawConfig());
1197
- const AWIKI_DEFAULT_BUILTIN_TENANT = AWIKI_BUILTIN_TENANT_CONFIG.tenants[AWIKI_BUILTIN_TENANT_CONFIG.defaultSlot];
1198
- //#endregion
1199
- //#region lib/types/domain.js
1200
- /** Client-safe AWiki Handle provider domain constants and validation. */
1201
- /** Default Handle provider domain for new AWiki deployments. */
1202
- const DEFAULT_AWIKI_DOMAIN = AWIKI_DEFAULT_BUILTIN_TENANT.didHost;
1203
- /** Field carrying the Handle provider domain in the AWiki settings namespace. */
1204
- const AWIKI_DOMAIN_FIELD = "domain";
1205
- /** Settings namespace owned by the AWiki plugin. */
1206
- const AWIKI_SETTINGS_NAMESPACE = "awiki";
1207
- /** Normalize and validate one DNS provider domain. */
1208
- function normalizeAwikiDomain(raw, field = "domain") {
1209
- const value = raw.trim().toLowerCase();
1210
- const valid = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(value);
1211
- if (value.length > 253 || !valid) throw new TypeError(`awiki: ${field} must contain a valid DNS domain`);
1212
- return value;
1213
- }
1214
- //#endregion
1215
1290
  //#region lib/types/settings.js
1216
1291
  /** Durable AWiki settings shared by the Host service and browser settings page. */
1217
1292
  /** Durable AWiki schema exposed through the DSH settings service. */
@@ -1221,25 +1296,6 @@ function validateAwikiSettings(value) {
1221
1296
  if (normalizeAwikiDomain(value.domain) !== value.domain) throw new TypeError("awiki: domain must be lowercase and must not contain surrounding whitespace");
1222
1297
  }
1223
1298
  //#endregion
1224
- //#region lib/types/settings-rpc-contract.js
1225
- /** Dedicated Connection channel; the Host registers it with loopback authority. */
1226
- const AWIKI_SETTINGS_RPC_CHANNEL = "/awiki-settings";
1227
- /** Supported channel-relative operations. */
1228
- const AWIKI_SETTINGS_RPC_ENDPOINTS = {
1229
- describe: "describe",
1230
- setDomain: "set-domain",
1231
- resetDomain: "reset-domain",
1232
- describeTenants: "describe-tenants",
1233
- createTenant: "create-tenant",
1234
- renameTenant: "rename-tenant",
1235
- switchTenant: "switch-tenant",
1236
- archiveTenant: "archive-tenant",
1237
- describeUpdatePolicy: "describe-update-policy",
1238
- refreshUpdatePolicy: "refresh-update-policy",
1239
- describeDesktopUpdate: "describe-desktop-update",
1240
- refreshDesktopUpdate: "refresh-desktop-update"
1241
- };
1242
- //#endregion
1243
1299
  //#region lib/types/settings-rpc.js
1244
1300
  /** Loopback-only Host transport for AWiki's durable plugin settings. */
1245
1301
  function isRecord$4(value) {
@@ -1464,7 +1520,7 @@ function createAwikiSettingsRpcHandler(getProvider, tenantManagement) {
1464
1520
  };
1465
1521
  else return badRequest();
1466
1522
  try {
1467
- await provider.mutate(settingsNamespace(AWIKI_SETTINGS_NAMESPACE), [operation], revision);
1523
+ await provider.mutate(AWIKI_SETTINGS_NAMESPACE, [operation], revision);
1468
1524
  const current = view(provider);
1469
1525
  return current === void 0 ? unavailable() : {
1470
1526
  ok: true,
@@ -2256,7 +2312,7 @@ var DshAwikiListenerAgentRuntime = class {
2256
2312
  agent.followup(message);
2257
2313
  await agent.whenIdle();
2258
2314
  await this.ctx.sessions.flush(agent.session);
2259
- const output = finalAssistantText(agent.session.events.slice(firstSeq), message.id);
2315
+ const output = finalAssistantText(agent.session.snapshotEvents(SessionLogOffset(firstSeq)), message.id);
2260
2316
  if (output === void 0) throw new Error("awiki listener: Agent produced no completed text response");
2261
2317
  return output;
2262
2318
  }
@@ -3173,8 +3229,8 @@ function legacyDocument(seed, usePreRegistryDefault) {
3173
3229
  //#endregion
3174
3230
  //#region lib/types/package-version.generated.js
3175
3231
  /** Generated from package.json by scripts/sync-package-versions.mjs. */
3176
- const DSH_AWIKI_PACKAGE_VERSION = "0.3.10";
3177
- const DSH_AWIKI_MODEL_PROXY_PACKAGE_VERSION = "0.1.6";
3232
+ const DSH_AWIKI_PACKAGE_VERSION = "0.3.11-rc.1";
3233
+ const DSH_AWIKI_MODEL_PROXY_PACKAGE_VERSION = "0.1.7-rc.1";
3178
3234
  //#endregion
3179
3235
  //#region lib/types/update-policy.js
3180
3236
  /** Tenant-scoped DSH AWiki plugin update policy and verified cache. */
@@ -3591,6 +3647,7 @@ const FAILURE_CODES = /* @__PURE__ */ new Set([
3591
3647
  "invalid-otp",
3592
3648
  "challenge-expired",
3593
3649
  "handle-unavailable",
3650
+ "short-handle-invite-required",
3594
3651
  "not-found",
3595
3652
  "forbidden",
3596
3653
  "device-rejoin-required",
@@ -3628,6 +3685,7 @@ const FAILURE_MESSAGES = {
3628
3685
  "invalid-otp": "The AWiki verification code is invalid.",
3629
3686
  "challenge-expired": "The AWiki verification challenge expired.",
3630
3687
  "handle-unavailable": "The requested AWiki handle is unavailable.",
3688
+ "short-handle-invite-required": "A new one- through four-character AWiki handle requires an invitation.",
3631
3689
  "not-found": "The requested AWiki resource was not found.",
3632
3690
  "forbidden": "The AWiki operation is not permitted.",
3633
3691
  "device-rejoin-required": "This device credential was revoked and must join the Handle again.",
@@ -3910,7 +3968,12 @@ function normalizeRecoveryPrepareRequest(request) {
3910
3968
  };
3911
3969
  }
3912
3970
  const IDENTITY_ACCESS_RESPONSE_MAX_BYTES = 65536;
3971
+ const DID_URI = /^did:[a-z0-9]+:(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})+(?::(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})+)*$/u;
3972
+ const DID_URI_MAX_CHARACTERS = 2048;
3913
3973
  const SERVER_INFO_RESPONSE_MAX_BYTES = 65536;
3974
+ function isBoundedDidUri(value) {
3975
+ return typeof value === "string" && value.length <= DID_URI_MAX_CHARACTERS && DID_URI.test(value);
3976
+ }
3914
3977
  /** Read one untrusted discovery response without buffering beyond the fixed Host limit. */
3915
3978
  async function readBoundedResponseText(response, maxBytes) {
3916
3979
  const declaredLength = response.headers.get("content-length");
@@ -3953,7 +4016,7 @@ function identityAccessTarget(request, configuredDomain) {
3953
4016
  const dot = handle.indexOf(".");
3954
4017
  const localPart = (dot < 0 ? handle : handle.slice(0, dot)).trim();
3955
4018
  const domain = (dot < 0 ? configuredDomain : handle.slice(dot + 1)).trim().replace(/\.$/u, "");
3956
- if (localPart.length === 0 || domain !== configuredDomain) return void 0;
4019
+ if (registrationHandleLocalPart(localPart) !== localPart || domain !== configuredDomain) return void 0;
3957
4020
  return {
3958
4021
  localPart,
3959
4022
  fullHandle: `${localPart}.${configuredDomain}`
@@ -4976,7 +5039,7 @@ let AwikiService = (() => {
4976
5039
  this.startupUserServiceDomain = this.resolved.userServiceDomain;
4977
5040
  ctx.inject(["settings"], (settingsCtx) => {
4978
5041
  const provider = settingsCtx.settings;
4979
- const settingsScope = settingsCtx.settings.register(settingsNamespace(AWIKI_SETTINGS_NAMESPACE), AwikiSettingsSchema, {
5042
+ const settingsScope = settingsCtx.settings.register(AWIKI_SETTINGS_NAMESPACE, AwikiSettingsSchema, {
4980
5043
  base: { domain: this.resolved.userServiceDomain },
4981
5044
  applies: "restart",
4982
5045
  validate: validateAwikiSettings
@@ -4991,7 +5054,7 @@ let AwikiService = (() => {
4991
5054
  }, "awiki: release settings namespace");
4992
5055
  });
4993
5056
  ctx.inject(["connection"], (connectionCtx) => {
4994
- connectionCtx.connection.rpc.handle(AWIKI_SETTINGS_RPC_CHANNEL, createAwikiSettingsRpcHandler(() => this.settingsProvider, {
5057
+ registerAwikiSettingsTransport(connectionCtx.connection, createAwikiSettingsRpcHandler(() => this.settingsProvider, {
4995
5058
  describe: () => this.getTenantRegistryView(),
4996
5059
  create: (displayName, domain) => this.createCustomTenant(displayName, domain),
4997
5060
  rename: (tenantId, displayName) => this.renameCustomTenant(tenantId, displayName),
@@ -5001,7 +5064,7 @@ let AwikiService = (() => {
5001
5064
  refreshUpdate: () => this.refreshUpdatePolicy(),
5002
5065
  describeDesktopUpdate: () => this.getDesktopUpdate(),
5003
5066
  refreshDesktopUpdate: () => this.refreshDesktopUpdate()
5004
- }), { authority: "loopback" });
5067
+ }));
5005
5068
  });
5006
5069
  ctx.inject(["workspaceRegistry"], (workspaceCtx) => {
5007
5070
  this.workspaceContext = workspaceCtx;
@@ -5627,7 +5690,7 @@ let AwikiService = (() => {
5627
5690
  fullHandle: target.fullHandle
5628
5691
  }
5629
5692
  };
5630
- if (!response.ok) return {
5693
+ if (!response.ok && response.status !== 410) return {
5631
5694
  ok: false,
5632
5695
  error: failure("remote")
5633
5696
  };
@@ -5643,7 +5706,7 @@ let AwikiService = (() => {
5643
5706
  error: failure("remote")
5644
5707
  };
5645
5708
  const binding = value;
5646
- if (binding.handle !== target.fullHandle || typeof binding.did !== "string" || !binding.did.startsWith("did:") || typeof binding.status !== "string" || binding.status.length === 0) return {
5709
+ if (binding.handle !== target.fullHandle || !isBoundedDidUri(binding.did) || typeof binding.status !== "string" || binding.status.length === 0 || response.status === 410 && binding.status !== "revoked") return {
5647
5710
  ok: false,
5648
5711
  error: failure("remote")
5649
5712
  };
@@ -5662,6 +5725,14 @@ let AwikiService = (() => {
5662
5725
  }
5663
5726
  }
5664
5727
  async sendRegistrationOtp(request) {
5728
+ if (shortHandleInviteRequired(request.handle)) {
5729
+ const inspection = await this.inspectIdentityAccess({ handle: request.handle });
5730
+ if (!inspection.ok) return inspection;
5731
+ if (inspection.value.status === "available") return {
5732
+ ok: false,
5733
+ error: failure("short-handle-invite-required")
5734
+ };
5735
+ }
5665
5736
  this.pendingDeviceJoin = void 0;
5666
5737
  return this.run(async (client) => {
5667
5738
  if (await this.selectDeviceJoinSession(client) !== null) throw Object.assign(/* @__PURE__ */ new Error("join already exists"), {
@@ -5677,6 +5748,14 @@ let AwikiService = (() => {
5677
5748
  * @returns The new public identity or a closed failure.
5678
5749
  */
5679
5750
  async registerIdentity(request) {
5751
+ if (shortHandleInviteRequired(request.handle)) {
5752
+ const inspection = await this.inspectIdentityAccess({ handle: request.handle });
5753
+ if (!inspection.ok) return inspection;
5754
+ if (inspection.value.status === "available") return {
5755
+ ok: false,
5756
+ error: failure("short-handle-invite-required")
5757
+ };
5758
+ }
5680
5759
  this.pendingDeviceJoin = void 0;
5681
5760
  const result = await this.run(async (client) => {
5682
5761
  if (await this.selectDeviceJoinSession(client) !== null) throw Object.assign(/* @__PURE__ */ new Error("join already exists"), {
@@ -7107,4 +7186,4 @@ function containsUnexpectedBinary(value, seen) {
7107
7186
  return false;
7108
7187
  }
7109
7188
  //#endregion
7110
- export { AWIKI_CHINA_TENANT_ID, AWIKI_CLEAR_LOCAL_DATA_CONFIRMATION, AWIKI_DOMAIN_FIELD, AWIKI_EXTERNAL_HTTP_MAX_BODY_BYTES, AWIKI_GLOBAL_TENANT_ID, AWIKI_HISTORY_TOOL, AWIKI_IDENTITY_STATUS_TOOL, AWIKI_LIST_CONVERSATIONS_TOOL, AWIKI_LOGOUT_CONFIRMATION, AWIKI_MAIL_ACCOUNT_TOOL, AWIKI_MAIL_INBOX_TOOL, AWIKI_MAIL_MARK_READ_TOOL, AWIKI_MAIL_READ_TOOL, AWIKI_MAIL_SEND_TOOL, AWIKI_OFFICIAL_CATALOG_VERSION, AWIKI_SEND_ATTACHMENT_TOOL, AWIKI_SEND_MESSAGE_TOOL, AWIKI_SETTINGS_NAMESPACE, AWIKI_TENANT_REGISTRY_SCHEMA_VERSION, AwikiExternalHttpAuthError, AwikiService, AwikiService as default, AwikiSettingsSchema, Config, DEFAULT_ATTACHMENT_MAX_BYTES, DEFAULT_AWIKI_DOMAIN, DEFAULT_AWIKI_MESSAGE_SERVICE_DID, DEFAULT_AWIKI_SERVICE_URL, DEFAULT_IMAGE_ATTACHMENT_CACHE_MAX_BYTES, DEFAULT_POLL_INTERVAL_MS, DEFAULT_SUMMARY_MAX_INPUT_BYTES, DSH_AWIKI_MODEL_PROXY_VERSION, DSH_AWIKI_VERSION, MAX_SUMMARY_MESSAGES, compareVersions as compareAwikiPluginVersions, normalizeAwikiDomain, validateAwikiSettings };
7189
+ export { AWIKI_CHINA_TENANT_ID, AWIKI_CLEAR_LOCAL_DATA_CONFIRMATION, AWIKI_DOMAIN_FIELD, AWIKI_EXTERNAL_HTTP_MAX_BODY_BYTES, AWIKI_GLOBAL_TENANT_ID, AWIKI_HISTORY_TOOL, AWIKI_IDENTITY_STATUS_TOOL, AWIKI_LIST_CONVERSATIONS_TOOL, AWIKI_LOGOUT_CONFIRMATION, AWIKI_MAIL_ACCOUNT_TOOL, AWIKI_MAIL_INBOX_TOOL, AWIKI_MAIL_MARK_READ_TOOL, AWIKI_MAIL_READ_TOOL, AWIKI_MAIL_SEND_TOOL, AWIKI_OFFICIAL_CATALOG_VERSION, AWIKI_SEND_ATTACHMENT_TOOL, AWIKI_SEND_MESSAGE_TOOL, AWIKI_SETTINGS_NAMESPACE, AWIKI_TENANT_REGISTRY_SCHEMA_VERSION, AwikiExternalHttpAuthError, AwikiService, AwikiService as default, AwikiSettingsSchema, Config, DEFAULT_ATTACHMENT_MAX_BYTES, DEFAULT_AWIKI_DOMAIN, DEFAULT_AWIKI_MESSAGE_SERVICE_DID, DEFAULT_AWIKI_SERVICE_URL, DEFAULT_IMAGE_ATTACHMENT_CACHE_MAX_BYTES, DEFAULT_POLL_INTERVAL_MS, DEFAULT_SUMMARY_MAX_INPUT_BYTES, DSH_AWIKI_MODEL_PROXY_VERSION, DSH_AWIKI_VERSION, MAX_SUMMARY_MESSAGES, compareVersions as compareAwikiPluginVersions, normalizeAwikiDomain, registerAwikiLoopbackRpc, validateAwikiSettings };
@@ -1,14 +1,14 @@
1
1
  //#region lib/types/model-proxy-contract.js
2
2
  /** Browser-safe contracts for the loopback AWiki-hosted DeepSeek proxy channel. */
3
- const AWIKI_MODEL_PROXY_RPC_CHANNEL = "/awiki-model-proxy";
3
+ const AWIKI_MODEL_PROXY_RPC_CHANNEL = "/api";
4
4
  const AWIKI_MODEL_PROXY_RPC_ENDPOINTS = {
5
- capability: "capability",
6
- status: "status",
7
- usage: "usage",
8
- setEnabled: "set-enabled",
9
- createRecharge: "create-recharge",
10
- rechargeStatus: "recharge-status",
11
- closeRecharge: "close-recharge"
5
+ capability: "awiki-model-proxy/capability",
6
+ status: "awiki-model-proxy/status",
7
+ usage: "awiki-model-proxy/usage",
8
+ setEnabled: "awiki-model-proxy/set-enabled",
9
+ createRecharge: "awiki-model-proxy/create-recharge",
10
+ rechargeStatus: "awiki-model-proxy/recharge-status",
11
+ closeRecharge: "awiki-model-proxy/close-recharge"
12
12
  };
13
13
  function decodeModelProxyCapability(value) {
14
14
  return isRecord(value) && value.available === true && value.protocol === 1 ? {