@voobase/cli 0.1.1-nonprod.2039 → 0.1.1-nonprod.2051

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 (95) hide show
  1. package/dist-bundle/index.mjs +69 -61
  2. package/package.json +9 -6
  3. package/runtime-sdk/dist/auth/client.d.ts +14 -0
  4. package/runtime-sdk/dist/auth/client.js +28 -0
  5. package/runtime-sdk/dist/blob/client.d.ts +39 -0
  6. package/runtime-sdk/dist/blob/client.js +148 -0
  7. package/runtime-sdk/dist/browser/app.d.ts +142 -0
  8. package/runtime-sdk/dist/browser/app.js +256 -0
  9. package/runtime-sdk/dist/browser/errors.d.ts +39 -0
  10. package/runtime-sdk/dist/browser/errors.js +265 -0
  11. package/runtime-sdk/dist/browser.d.ts +5 -0
  12. package/runtime-sdk/dist/browser.js +5 -0
  13. package/runtime-sdk/dist/client.d.ts +16 -0
  14. package/runtime-sdk/dist/client.js +22 -0
  15. package/runtime-sdk/dist/cms/client.d.ts +39 -0
  16. package/runtime-sdk/dist/cms/client.js +56 -0
  17. package/runtime-sdk/dist/cms/media.d.ts +10 -0
  18. package/runtime-sdk/dist/cms/media.js +113 -0
  19. package/runtime-sdk/dist/cms/taxonomy.d.ts +8 -0
  20. package/runtime-sdk/dist/cms/taxonomy.js +77 -0
  21. package/runtime-sdk/dist/data-form/client.d.ts +19 -0
  22. package/runtime-sdk/dist/data-form/client.js +118 -0
  23. package/runtime-sdk/dist/data-form/contracts.d.ts +10 -0
  24. package/runtime-sdk/dist/data-form/contracts.js +33 -0
  25. package/runtime-sdk/dist/data-form/index.d.ts +3 -0
  26. package/runtime-sdk/dist/data-form/index.js +2 -0
  27. package/runtime-sdk/dist/data-form/types.d.ts +110 -0
  28. package/runtime-sdk/dist/data-form/types.js +1 -0
  29. package/runtime-sdk/dist/http.d.ts +27 -0
  30. package/runtime-sdk/dist/http.js +126 -0
  31. package/runtime-sdk/dist/index.d.ts +19 -0
  32. package/runtime-sdk/dist/index.js +14 -0
  33. package/runtime-sdk/dist/notification/client.d.ts +16 -0
  34. package/runtime-sdk/dist/notification/client.js +39 -0
  35. package/runtime-sdk/dist/notification/index.d.ts +1 -0
  36. package/runtime-sdk/dist/notification/index.js +1 -0
  37. package/runtime-sdk/dist/react/context.d.ts +18 -0
  38. package/runtime-sdk/dist/react/context.js +28 -0
  39. package/runtime-sdk/dist/react/hooks.d.ts +90 -0
  40. package/runtime-sdk/dist/react/hooks.js +172 -0
  41. package/runtime-sdk/dist/react.d.ts +2 -0
  42. package/runtime-sdk/dist/react.js +2 -0
  43. package/runtime-sdk/dist/session/browser.d.ts +25 -0
  44. package/runtime-sdk/dist/session/browser.js +60 -0
  45. package/runtime-sdk/dist/types/auth.d.ts +38 -0
  46. package/runtime-sdk/dist/types/auth.js +1 -0
  47. package/runtime-sdk/dist/types/cms.d.ts +93 -0
  48. package/runtime-sdk/dist/types/cms.js +1 -0
  49. package/runtime-sdk/dist/types/notification.d.ts +37 -0
  50. package/runtime-sdk/dist/types/notification.js +1 -0
  51. package/runtime-sdk/dist/types/object-storage.d.ts +58 -0
  52. package/runtime-sdk/dist/types/object-storage.js +1 -0
  53. package/runtime-sdk/dist/types/workflow.d.ts +52 -0
  54. package/runtime-sdk/dist/types/workflow.js +1 -0
  55. package/runtime-sdk/dist/workflow/client.d.ts +30 -0
  56. package/runtime-sdk/dist/workflow/client.js +45 -0
  57. package/scaffold-assets-manifest.json +373 -0
  58. package/template-blocks/assets.ts +95 -0
  59. package/template-blocks/contract/capabilities.ts +33 -0
  60. package/template-blocks/contract/facade-contract.ts +59 -0
  61. package/template-blocks/contract/index.ts +4 -0
  62. package/template-blocks/contract/path-builders.ts +76 -0
  63. package/template-blocks/contract/route-path-patterns-source.ts +222 -0
  64. package/template-blocks/contract/route-path-patterns.ts +210 -0
  65. package/template-blocks/contract/runtime-config.ts +256 -0
  66. package/template-blocks/dev-support/index.ts +2 -0
  67. package/template-blocks/dev-support/node/auth-shell.ts +31 -0
  68. package/template-blocks/dev-support/node/index.ts +3 -0
  69. package/template-blocks/dev-support/node/proxy.ts +133 -0
  70. package/template-blocks/dev-support/node/runtime-config.ts +163 -0
  71. package/template-blocks/dev-support/vite/auth-shell.ts +23 -0
  72. package/template-blocks/dev-support/vite/index.ts +3 -0
  73. package/template-blocks/dev-support/vite/proxy.ts +451 -0
  74. package/template-blocks/dev-support/vite/runtime-config.ts +107 -0
  75. package/template-blocks/legacy/app-core.ts +153 -0
  76. package/template-blocks/legacy/index.ts +10 -0
  77. package/template-blocks/legacy/lifecycle.ts +38 -0
  78. package/template-blocks/legacy/metadata.ts +59 -0
  79. package/template-blocks/legacy/pages.ts +156 -0
  80. package/template-blocks/legacy/react-lock.ts +1599 -0
  81. package/template-blocks/legacy/react.ts +823 -0
  82. package/template-blocks/legacy/tailwind.ts +1138 -0
  83. package/template-blocks/legacy/wrappers/auth.ts +105 -0
  84. package/template-blocks/legacy/wrappers/proxy.ts +250 -0
  85. package/template-blocks/legacy/wrappers/runtime.ts +535 -0
  86. package/template-blocks/protocol/auth-routes.ts +82 -0
  87. package/template-blocks/protocol/cms-routes.ts +81 -0
  88. package/template-blocks/protocol/index.ts +4 -0
  89. package/template-blocks/protocol/public-app-routes.ts +48 -0
  90. package/template-blocks/protocol/route-map.ts +75 -0
  91. package/template-blocks/routing.ts +62 -0
  92. package/template-blocks/server/html-injection.ts +45 -0
  93. package/template-blocks/server/proxy-routing.ts +65 -0
  94. package/template-blocks/server/request-context.ts +103 -0
  95. package/template-blocks/server/route-strip.ts +47 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voobase/cli",
3
- "version": "0.1.1-nonprod.2039",
3
+ "version": "0.1.1-nonprod.2051",
4
4
  "private": false,
5
5
  "platformDistributionProfile": {
6
6
  "name": "nonprod",
@@ -20,6 +20,9 @@
20
20
  "bin": {
21
21
  "platform": "dist-bundle/index.mjs"
22
22
  },
23
+ "engines": {
24
+ "node": ">=20.0.0"
25
+ },
23
26
  "scripts": {
24
27
  "dev": "tsx watch src/index.ts --help",
25
28
  "build": "corepack pnpm --filter @platform/sdk build && corepack pnpm --filter @platform/capability-auth build && corepack pnpm --filter @platform/capability-cms build && corepack pnpm --filter @platform/capability-data-form build && tsc -p tsconfig.json",
@@ -53,10 +56,10 @@
53
56
  "bundleDependencies": [],
54
57
  "platformDistributionBuild": {
55
58
  "channel": "nonprod",
56
- "version": "0.1.1-nonprod.2039",
57
- "sequence": 2039,
58
- "gitSha": "e5d1c1f",
59
- "fullGitSha": "e5d1c1f21da6f231f3c7d42fe227ae44b4b16ca1",
60
- "buildId": "0.1.1-nonprod.2039+e5d1c1f"
59
+ "version": "0.1.1-nonprod.2051",
60
+ "sequence": 2051,
61
+ "gitSha": "af1febe",
62
+ "fullGitSha": "af1febe76cef4519c4ed2150bdde045a61ff0390",
63
+ "buildId": "0.1.1-nonprod.2051+af1febe"
61
64
  }
62
65
  }
@@ -0,0 +1,14 @@
1
+ import { BaseRuntimeSdk, type RuntimeSdkOptions } from "../http.js";
2
+ import type { RuntimeEndUserAuthMe, RuntimeEndUserRoleRecord } from "../types/auth.js";
3
+ export declare class RuntimeAuthClient extends BaseRuntimeSdk {
4
+ constructor(options: RuntimeSdkOptions);
5
+ getCurrentEndUser(): Promise<RuntimeEndUserAuthMe>;
6
+ getCurrentEndUserRoles(): Promise<RuntimeEndUserRoleRecord[]>;
7
+ isSignedIn(): Promise<boolean>;
8
+ getMe(): Promise<RuntimeEndUserAuthMe>;
9
+ listMyRoles(): Promise<RuntimeEndUserRoleRecord[]>;
10
+ signOut(): Promise<{
11
+ app_id: string;
12
+ signed_out: true;
13
+ }>;
14
+ }
@@ -0,0 +1,28 @@
1
+ import { BaseRuntimeSdk } from "../http.js";
2
+ export class RuntimeAuthClient extends BaseRuntimeSdk {
3
+ constructor(options) {
4
+ super(options);
5
+ }
6
+ async getCurrentEndUser() {
7
+ return this.requestApp("/end-user-auth/me");
8
+ }
9
+ async getCurrentEndUserRoles() {
10
+ const result = await this.requestApp("/end-user-auth/roles");
11
+ return result.items;
12
+ }
13
+ async isSignedIn() {
14
+ const me = await this.getCurrentEndUser();
15
+ return me.access_state === "authenticated_and_ready";
16
+ }
17
+ async getMe() {
18
+ return this.getCurrentEndUser();
19
+ }
20
+ async listMyRoles() {
21
+ return this.getCurrentEndUserRoles();
22
+ }
23
+ async signOut() {
24
+ return this.requestApp("/end-user-auth/sign-out", {
25
+ method: "POST"
26
+ });
27
+ }
28
+ }
@@ -0,0 +1,39 @@
1
+ import { BaseRuntimeSdk, type RuntimeSdkOptions } from "../http.js";
2
+ import type { RuntimeBlobHydrateResponse, RuntimeBlobUploadSession, RuntimeCompleteBlobUploadInput, RuntimeCompleteBlobUploadResult, RuntimeCreateBlobUploadSessionInput, RuntimeHydrateBlobRefsInput, RuntimeHydrateRecordBlobsInput } from "../types/object-storage.js";
3
+ export type RuntimeBlobBinaryBody = Blob | ArrayBuffer | ArrayBufferView;
4
+ export declare class RuntimeBlobClient extends BaseRuntimeSdk {
5
+ private cachedUploadTicket;
6
+ constructor(options: RuntimeSdkOptions);
7
+ createUploadSession(input: RuntimeCreateBlobUploadSessionInput): Promise<RuntimeBlobUploadSession>;
8
+ uploadBinary(args: {
9
+ uploadUrl: string;
10
+ body: RuntimeBlobBinaryBody;
11
+ contentType: string;
12
+ headers?: Record<string, string>;
13
+ }): Promise<void>;
14
+ completeUpload(uploadSessionId: string, input?: RuntimeCompleteBlobUploadInput): Promise<RuntimeCompleteBlobUploadResult>;
15
+ upload(args: RuntimeCreateBlobUploadSessionInput & {
16
+ body: RuntimeBlobBinaryBody;
17
+ sha256?: string;
18
+ }): Promise<RuntimeCompleteBlobUploadResult>;
19
+ uploadFile(file: Blob & {
20
+ name?: string;
21
+ }, args?: Omit<RuntimeCreateBlobUploadSessionInput, "original_filename" | "content_type" | "size_bytes"> & {
22
+ original_filename?: string;
23
+ content_type?: string;
24
+ sha256?: string;
25
+ }): Promise<RuntimeCompleteBlobUploadResult>;
26
+ uploadFiles(files: Array<Blob & {
27
+ name?: string;
28
+ }>, args?: Omit<RuntimeCreateBlobUploadSessionInput, "original_filename" | "content_type" | "size_bytes"> & {
29
+ original_filenames?: string[];
30
+ content_types?: string[];
31
+ sha256_list?: Array<string | undefined>;
32
+ }): Promise<RuntimeCompleteBlobUploadResult[]>;
33
+ hydrateBlobRefs(args: RuntimeHydrateBlobRefsInput): Promise<RuntimeBlobHydrateResponse>;
34
+ hydrateRecordBlobs(args: RuntimeHydrateRecordBlobsInput): Promise<RuntimeBlobHydrateResponse>;
35
+ private createUploadTicket;
36
+ private withUploadTicket;
37
+ private clearUploadTicket;
38
+ private ensureUploadTicket;
39
+ }
@@ -0,0 +1,148 @@
1
+ import { BaseRuntimeSdk, RuntimeApiError } from "../http.js";
2
+ const UPLOAD_TICKET_REFRESH_SKEW_MS = 30_000;
3
+ const UPLOAD_TICKET_RETRYABLE_CODES = new Set(["missing_credentials", "ticket_invalid"]);
4
+ export class RuntimeBlobClient extends BaseRuntimeSdk {
5
+ cachedUploadTicket = null;
6
+ constructor(options) {
7
+ super(options);
8
+ }
9
+ async createUploadSession(input) {
10
+ return this.withUploadTicket((ticket) => this.requestApp("/blobs/upload-sessions", {
11
+ method: "POST",
12
+ headers: {
13
+ Authorization: `Ticket ${ticket}`
14
+ },
15
+ body: JSON.stringify(input)
16
+ }));
17
+ }
18
+ async uploadBinary(args) {
19
+ await this.withUploadTicket(async (ticket) => {
20
+ const url = /^https?:\/\//i.test(args.uploadUrl)
21
+ ? new URL(args.uploadUrl)
22
+ : this.buildRequestUrl(args.uploadUrl);
23
+ const headers = new Headers(args.headers);
24
+ headers.set("Authorization", `Ticket ${ticket}`);
25
+ headers.set("Content-Type", args.contentType);
26
+ await this.requestVoidUrl(url, {
27
+ method: "PUT",
28
+ headers,
29
+ body: toRequestBody(args.body)
30
+ });
31
+ });
32
+ }
33
+ async completeUpload(uploadSessionId, input = {}) {
34
+ return this.withUploadTicket((ticket) => this.requestApp(`/blobs/upload-sessions/${encodeURIComponent(uploadSessionId)}/complete`, {
35
+ method: "POST",
36
+ headers: {
37
+ Authorization: `Ticket ${ticket}`
38
+ },
39
+ body: JSON.stringify(input)
40
+ }));
41
+ }
42
+ async upload(args) {
43
+ const { body, sha256, ...createInput } = args;
44
+ const session = await this.createUploadSession(createInput);
45
+ const contentType = args.content_type?.trim();
46
+ if (!contentType) {
47
+ throw new Error("content_type is required for runtime blob upload.");
48
+ }
49
+ await this.uploadBinary({
50
+ uploadUrl: session.upload_url,
51
+ body,
52
+ contentType,
53
+ headers: session.headers
54
+ });
55
+ return this.completeUpload(session.upload_session_id, {
56
+ ...(sha256 ? { sha256 } : {}),
57
+ ...(args.size_bytes !== undefined ? { size_bytes: args.size_bytes } : {})
58
+ });
59
+ }
60
+ async uploadFile(file, args = {}) {
61
+ const originalFilename = args.original_filename?.trim() || file.name?.trim() || "blob.bin";
62
+ const contentType = args.content_type?.trim() || file.type?.trim() || "application/octet-stream";
63
+ return this.upload({
64
+ ...args,
65
+ original_filename: originalFilename,
66
+ content_type: contentType,
67
+ size_bytes: Number.isFinite(file.size) ? file.size : undefined,
68
+ body: file
69
+ });
70
+ }
71
+ async uploadFiles(files, args = {}) {
72
+ const results = [];
73
+ for (const [index, file] of files.entries()) {
74
+ results.push(await this.uploadFile(file, {
75
+ ...args,
76
+ ...(args.original_filenames?.[index] ? { original_filename: args.original_filenames[index] } : {}),
77
+ ...(args.content_types?.[index] ? { content_type: args.content_types[index] } : {}),
78
+ ...(args.sha256_list?.[index] ? { sha256: args.sha256_list[index] } : {})
79
+ }));
80
+ }
81
+ return results;
82
+ }
83
+ async hydrateBlobRefs(args) {
84
+ return this.requestApp("/blobs/hydrate", {
85
+ method: "POST",
86
+ body: JSON.stringify({
87
+ items: args.items
88
+ })
89
+ });
90
+ }
91
+ async hydrateRecordBlobs(args) {
92
+ return this.requestApp("/blobs/hydrate", {
93
+ method: "POST",
94
+ body: JSON.stringify({
95
+ resource_key: args.resourceKey,
96
+ record_id: args.recordId
97
+ })
98
+ });
99
+ }
100
+ async createUploadTicket() {
101
+ return this.requestApp("/blobs/upload-ticket", {
102
+ method: "POST"
103
+ });
104
+ }
105
+ async withUploadTicket(runner) {
106
+ const ticket = await this.ensureUploadTicket();
107
+ try {
108
+ return await runner(ticket);
109
+ }
110
+ catch (error) {
111
+ if (!isUploadTicketRetryableError(error)) {
112
+ throw error;
113
+ }
114
+ this.clearUploadTicket();
115
+ return runner(await this.ensureUploadTicket());
116
+ }
117
+ }
118
+ clearUploadTicket() {
119
+ this.cachedUploadTicket = null;
120
+ }
121
+ async ensureUploadTicket() {
122
+ if (this.cachedUploadTicket && this.cachedUploadTicket.expiresAtMs - UPLOAD_TICKET_REFRESH_SKEW_MS > Date.now()) {
123
+ return this.cachedUploadTicket.value;
124
+ }
125
+ const next = await this.createUploadTicket();
126
+ const expiresAtMs = Date.parse(next.expires_at);
127
+ this.cachedUploadTicket = {
128
+ value: next.upload_ticket,
129
+ expiresAtMs: Number.isFinite(expiresAtMs) ? expiresAtMs : Date.now()
130
+ };
131
+ return next.upload_ticket;
132
+ }
133
+ }
134
+ function toRequestBody(body) {
135
+ if (body instanceof ArrayBuffer) {
136
+ return body;
137
+ }
138
+ if (ArrayBuffer.isView(body)) {
139
+ return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
140
+ }
141
+ return body;
142
+ }
143
+ function isUploadTicketRetryableError(error) {
144
+ return (error instanceof RuntimeApiError &&
145
+ error.status === 401 &&
146
+ typeof error.code === "string" &&
147
+ UPLOAD_TICKET_RETRYABLE_CODES.has(error.code));
148
+ }
@@ -0,0 +1,142 @@
1
+ import { type BrowserSessionStore, type BrowserSessionStoreOptions } from "../session/browser.js";
2
+ import { type RuntimeCmsMediaUrlOptions } from "../cms/media.js";
3
+ import type { RuntimeWorkflowActionResult, RuntimeWorkflowObjectState, RuntimeWorkflowStartResult, RuntimeWorkflowTaskList, RuntimeWorkflowTimelineItem } from "../types/workflow.js";
4
+ import type { RuntimeNotificationAnnouncements, RuntimeNotificationCommandResult, RuntimeNotificationInboxItemStatus, RuntimeNotificationInboxList, RuntimeNotificationUnreadCount } from "../types/notification.js";
5
+ import type { RuntimeCmsCategoryNode, RuntimeCmsCategoryTreeResponse, RuntimeCmsCollectionListResponse, RuntimeCmsCollectionMetaResponse, RuntimeCmsDeliveryListResponse, RuntimeCmsImageSet, RuntimeCmsItemDeliveryPayload } from "../types/cms.js";
6
+ import type { RuntimeEndUserAuthMe, RuntimeEndUserRoleRecord } from "../types/auth.js";
7
+ import type { RuntimeBlobHydrateResponse, RuntimeCompleteBlobUploadResult, RuntimeCreateBlobUploadSessionInput, RuntimeHydrateBlobRefsInput, RuntimeHydrateRecordBlobsInput } from "../types/object-storage.js";
8
+ export type BrowserRuntimeAppOptions = {
9
+ baseUrl: string;
10
+ appId: string;
11
+ env?: "preview" | "prod";
12
+ session?: BrowserSessionStore;
13
+ sessionOptions?: BrowserSessionStoreOptions;
14
+ authPath?: string;
15
+ fetchImpl?: typeof fetch;
16
+ };
17
+ export declare function createBrowserRuntimeApp(options: BrowserRuntimeAppOptions): {
18
+ sdk: import("../client.js").PlatformRuntimeSdk;
19
+ session: BrowserSessionStore;
20
+ buildSignInUrl(returnTo?: string): string;
21
+ resolveAccess(me: RuntimeEndUserAuthMe | null | undefined): import("./errors.js").BrowserRuntimeAccessResolution;
22
+ classifyError(error: unknown): import("./errors.js").BrowserRuntimeErrorResolution;
23
+ classifyWorkflowError(error: unknown, params?: {
24
+ operationLabel?: string;
25
+ }): import("./errors.js").BrowserWorkflowErrorResolution;
26
+ getErrorMessage(error: unknown, fallback?: string): string;
27
+ getWorkflowErrorMessage(error: unknown, fallback?: string, params?: {
28
+ operationLabel?: string;
29
+ }): string;
30
+ getCurrentEndUser(): Promise<RuntimeEndUserAuthMe>;
31
+ getCurrentEndUserRoles(): Promise<RuntimeEndUserRoleRecord[]>;
32
+ isSignedIn(): Promise<boolean>;
33
+ getMe(): Promise<RuntimeEndUserAuthMe>;
34
+ listMyRoles(): Promise<RuntimeEndUserRoleRecord[]>;
35
+ listMyTasks(args?: {
36
+ status?: string;
37
+ limit?: number;
38
+ cursor?: string;
39
+ }): Promise<RuntimeWorkflowTaskList>;
40
+ listMyNotifications(args?: {
41
+ status?: RuntimeNotificationInboxItemStatus;
42
+ inboxType?: "task_projection" | "notification" | "alert" | "announcement";
43
+ limit?: number;
44
+ }): Promise<RuntimeNotificationInboxList>;
45
+ getMyNotificationUnreadCount(): Promise<RuntimeNotificationUnreadCount>;
46
+ listMyAnnouncements(args?: {
47
+ limit?: number;
48
+ }): Promise<RuntimeNotificationAnnouncements>;
49
+ markNotificationRead(itemId: string): Promise<RuntimeNotificationCommandResult>;
50
+ dismissNotification(itemId: string): Promise<RuntimeNotificationCommandResult>;
51
+ getWorkflowObjectState(args: {
52
+ objectType: string;
53
+ objectId: string;
54
+ }): Promise<RuntimeWorkflowObjectState>;
55
+ startWorkflow(args: {
56
+ definitionKey: string;
57
+ objectType: string;
58
+ objectId: string;
59
+ payload?: Record<string, unknown>;
60
+ }): Promise<RuntimeWorkflowStartResult>;
61
+ performWorkflowAction(args: {
62
+ instanceId: string;
63
+ actionKey: string;
64
+ comment?: string;
65
+ payload?: Record<string, unknown>;
66
+ }): Promise<RuntimeWorkflowActionResult>;
67
+ listWorkflowTimeline(args: {
68
+ objectType: string;
69
+ objectId: string;
70
+ }): Promise<RuntimeWorkflowTimelineItem[]>;
71
+ listCmsItems(args: {
72
+ tenantId: string;
73
+ collection: string;
74
+ page?: number;
75
+ pageSize?: number;
76
+ categoryId?: string;
77
+ tags?: string[];
78
+ featured?: boolean;
79
+ sortField?: string;
80
+ sortDirection?: "asc" | "desc";
81
+ q?: string;
82
+ }): Promise<RuntimeCmsDeliveryListResponse>;
83
+ listCmsCollections(args: {
84
+ tenantId: string;
85
+ }): Promise<RuntimeCmsCollectionListResponse>;
86
+ uploadBlob(args: RuntimeCreateBlobUploadSessionInput & {
87
+ body: Blob | ArrayBuffer | ArrayBufferView;
88
+ sha256?: string;
89
+ }): Promise<RuntimeCompleteBlobUploadResult>;
90
+ uploadBlobFile(file: Blob & {
91
+ name?: string;
92
+ }, args?: Omit<RuntimeCreateBlobUploadSessionInput, "original_filename" | "content_type" | "size_bytes"> & {
93
+ original_filename?: string;
94
+ content_type?: string;
95
+ sha256?: string;
96
+ }): Promise<RuntimeCompleteBlobUploadResult>;
97
+ uploadBlobFiles(files: Array<Blob & {
98
+ name?: string;
99
+ }>, args?: Omit<RuntimeCreateBlobUploadSessionInput, "original_filename" | "content_type" | "size_bytes"> & {
100
+ original_filenames?: string[];
101
+ content_types?: string[];
102
+ sha256_list?: Array<string | undefined>;
103
+ }): Promise<RuntimeCompleteBlobUploadResult[]>;
104
+ hydrateBlobRefs(args: RuntimeHydrateBlobRefsInput): Promise<RuntimeBlobHydrateResponse>;
105
+ hydrateRecordBlobs(args: RuntimeHydrateRecordBlobsInput): Promise<RuntimeBlobHydrateResponse>;
106
+ getCmsCollectionMeta(args: {
107
+ tenantId: string;
108
+ collection: string;
109
+ }): Promise<RuntimeCmsCollectionMetaResponse>;
110
+ listCmsCategories(args: {
111
+ tenantId: string;
112
+ collection: string;
113
+ }): Promise<RuntimeCmsCategoryTreeResponse>;
114
+ listCmsCategoryNodes(args: {
115
+ tenantId: string;
116
+ collection: string;
117
+ }): Promise<RuntimeCmsCategoryNode[]>;
118
+ getCmsItemBySlug(args: {
119
+ tenantId: string;
120
+ collection: string;
121
+ slug: string;
122
+ }): Promise<RuntimeCmsItemDeliveryPayload>;
123
+ getCmsItemById(args: {
124
+ tenantId: string;
125
+ collection: string;
126
+ itemId: string;
127
+ }): Promise<RuntimeCmsItemDeliveryPayload>;
128
+ resolveCmsImageSet(value: unknown, options?: RuntimeCmsMediaUrlOptions): RuntimeCmsImageSet | null;
129
+ resolveCmsImageUrl(value: unknown, options?: RuntimeCmsMediaUrlOptions): string | null;
130
+ resolveCmsCoverImageSet(item: RuntimeCmsItemDeliveryPayload, options?: RuntimeCmsMediaUrlOptions): RuntimeCmsImageSet | null;
131
+ resolveCmsCoverImageUrl(item: RuntimeCmsItemDeliveryPayload, options?: RuntimeCmsMediaUrlOptions): string | null;
132
+ buildCmsCategoryNameMap(source: RuntimeCmsCollectionMetaResponse | RuntimeCmsCategoryNode[] | Map<string, string> | null | undefined): Map<string, string>;
133
+ resolveCmsCategoryName(categoryId: unknown, source: RuntimeCmsCollectionMetaResponse | RuntimeCmsCategoryNode[] | Map<string, string> | null | undefined, fallback?: string): string;
134
+ resolveCmsItemCategoryName(item: RuntimeCmsItemDeliveryPayload, source: RuntimeCmsCollectionMetaResponse | RuntimeCmsCategoryNode[] | Map<string, string> | null | undefined, fallback?: string): string;
135
+ resolveCmsTagLabels(value: unknown): string[];
136
+ resolveCmsItemTagLabels(item: RuntimeCmsItemDeliveryPayload): string[];
137
+ signOut(): Promise<void>;
138
+ ensureAuthenticated(args?: {
139
+ returnTo?: string;
140
+ redirectToSignIn?: boolean;
141
+ }): Promise<RuntimeEndUserAuthMe | null>;
142
+ };
@@ -0,0 +1,256 @@
1
+ import { createBrowserRuntimeSdk, createBrowserSessionStore } from "../session/browser.js";
2
+ import { classifyBrowserRuntimeError, classifyBrowserWorkflowError, getBrowserRuntimeErrorMessage, getBrowserWorkflowErrorMessage, resolveEndUserAccess } from "./errors.js";
3
+ import { resolveCmsCoverImageSet as resolveRuntimeCmsCoverImageSet, resolveCmsCoverImageUrl as resolveRuntimeCmsCoverImageUrl, resolveCmsImageSet as resolveRuntimeCmsImageSet, resolveCmsImageUrl as resolveRuntimeCmsImageUrl } from "../cms/media.js";
4
+ import { buildCmsCategoryNameMap as buildRuntimeCmsCategoryNameMap, resolveCmsCategoryName as resolveRuntimeCmsCategoryName, resolveCmsItemCategoryName as resolveRuntimeCmsItemCategoryName, resolveCmsItemTagLabels as resolveRuntimeCmsItemTagLabels, resolveCmsTagLabels as resolveRuntimeCmsTagLabels } from "../cms/taxonomy.js";
5
+ export function createBrowserRuntimeApp(options) {
6
+ const session = options.session ?? createBrowserSessionStore(options.sessionOptions);
7
+ const sdk = createBrowserRuntimeSdk({
8
+ baseUrl: options.baseUrl,
9
+ appId: options.appId,
10
+ env: options.env,
11
+ fetchImpl: options.fetchImpl,
12
+ session,
13
+ });
14
+ const authPath = options.authPath ?? "/auth";
15
+ return {
16
+ sdk,
17
+ session,
18
+ buildSignInUrl(returnTo = getCurrentLocationPath(authPath)) {
19
+ const url = new URL(authPath, window.location.origin);
20
+ url.searchParams.set("return_to", normalizeReturnToTarget(returnTo, authPath));
21
+ return url.toString();
22
+ },
23
+ resolveAccess(me) {
24
+ return resolveEndUserAccess(me);
25
+ },
26
+ classifyError(error) {
27
+ return classifyBrowserRuntimeError(error);
28
+ },
29
+ classifyWorkflowError(error, params = {}) {
30
+ return classifyBrowserWorkflowError(error, {
31
+ appId: options.appId,
32
+ operationLabel: params.operationLabel
33
+ });
34
+ },
35
+ getErrorMessage(error, fallback = "运行时请求失败。") {
36
+ return getBrowserRuntimeErrorMessage(error, fallback);
37
+ },
38
+ getWorkflowErrorMessage(error, fallback = "Workflow 请求失败。", params = {}) {
39
+ return getBrowserWorkflowErrorMessage(error, fallback, {
40
+ appId: options.appId,
41
+ operationLabel: params.operationLabel
42
+ });
43
+ },
44
+ async getCurrentEndUser() {
45
+ return sdk.auth.getCurrentEndUser();
46
+ },
47
+ async getCurrentEndUserRoles() {
48
+ return sdk.auth.getCurrentEndUserRoles();
49
+ },
50
+ async isSignedIn() {
51
+ return sdk.auth.isSignedIn();
52
+ },
53
+ async getMe() {
54
+ return sdk.auth.getCurrentEndUser();
55
+ },
56
+ async listMyRoles() {
57
+ return sdk.auth.getCurrentEndUserRoles();
58
+ },
59
+ async listMyTasks(args) {
60
+ return sdk.workflow.listMyTasks(args);
61
+ },
62
+ async listMyNotifications(args) {
63
+ return sdk.notification.listMyInbox(args);
64
+ },
65
+ async getMyNotificationUnreadCount() {
66
+ return sdk.notification.getMyUnreadCount();
67
+ },
68
+ async listMyAnnouncements(args) {
69
+ return sdk.notification.listMyAnnouncements(args);
70
+ },
71
+ async markNotificationRead(itemId) {
72
+ return sdk.notification.markRead(itemId);
73
+ },
74
+ async dismissNotification(itemId) {
75
+ return sdk.notification.dismiss(itemId);
76
+ },
77
+ async getWorkflowObjectState(args) {
78
+ return sdk.workflow.getObjectState(args);
79
+ },
80
+ async startWorkflow(args) {
81
+ return sdk.workflow.startObjectWorkflow(args);
82
+ },
83
+ async performWorkflowAction(args) {
84
+ return sdk.workflow.performAction(args);
85
+ },
86
+ async listWorkflowTimeline(args) {
87
+ return sdk.workflow.listTimeline(args);
88
+ },
89
+ async listCmsItems(args) {
90
+ return sdk.cms.listItems(args);
91
+ },
92
+ async listCmsCollections(args) {
93
+ return sdk.cms.listCollections(args);
94
+ },
95
+ async uploadBlob(args) {
96
+ return sdk.blob.upload(args);
97
+ },
98
+ async uploadBlobFile(file, args) {
99
+ return sdk.blob.uploadFile(file, args);
100
+ },
101
+ async uploadBlobFiles(files, args) {
102
+ return sdk.blob.uploadFiles(files, args);
103
+ },
104
+ async hydrateBlobRefs(args) {
105
+ return sdk.blob.hydrateBlobRefs(args);
106
+ },
107
+ async hydrateRecordBlobs(args) {
108
+ return sdk.blob.hydrateRecordBlobs(args);
109
+ },
110
+ async getCmsCollectionMeta(args) {
111
+ return sdk.cms.getCollectionMeta(args);
112
+ },
113
+ async listCmsCategories(args) {
114
+ return sdk.cms.listCategories(args);
115
+ },
116
+ async listCmsCategoryNodes(args) {
117
+ const result = await sdk.cms.listCategories(args);
118
+ return Array.isArray(result?.nodes) ? result.nodes : [];
119
+ },
120
+ async getCmsItemBySlug(args) {
121
+ return sdk.cms.getItemBySlug(args);
122
+ },
123
+ async getCmsItemById(args) {
124
+ return sdk.cms.getItemById(args);
125
+ },
126
+ resolveCmsImageSet(value, options = {}) {
127
+ return resolveRuntimeCmsImageSet(value, withBrowserProtocol(options));
128
+ },
129
+ resolveCmsImageUrl(value, options = {}) {
130
+ return resolveRuntimeCmsImageUrl(value, withBrowserProtocol(options));
131
+ },
132
+ resolveCmsCoverImageSet(item, options = {}) {
133
+ return resolveRuntimeCmsCoverImageSet(item, withBrowserProtocol(options));
134
+ },
135
+ resolveCmsCoverImageUrl(item, options = {}) {
136
+ return resolveRuntimeCmsCoverImageUrl(item, withBrowserProtocol(options));
137
+ },
138
+ buildCmsCategoryNameMap(source) {
139
+ return buildRuntimeCmsCategoryNameMap(source);
140
+ },
141
+ resolveCmsCategoryName(categoryId, source, fallback = "未分类") {
142
+ return resolveRuntimeCmsCategoryName(categoryId, source, fallback);
143
+ },
144
+ resolveCmsItemCategoryName(item, source, fallback = "未分类") {
145
+ return resolveRuntimeCmsItemCategoryName(item, source, fallback);
146
+ },
147
+ resolveCmsTagLabels(value) {
148
+ return resolveRuntimeCmsTagLabels(value);
149
+ },
150
+ resolveCmsItemTagLabels(item) {
151
+ return resolveRuntimeCmsItemTagLabels(item);
152
+ },
153
+ async signOut() {
154
+ try {
155
+ await sdk.auth.signOut();
156
+ }
157
+ finally {
158
+ session.clearToken();
159
+ }
160
+ },
161
+ async ensureAuthenticated(args = {}) {
162
+ const shouldRedirect = args.redirectToSignIn ?? true;
163
+ if (!session.readToken()) {
164
+ if (shouldRedirect) {
165
+ window.location.assign(this.buildSignInUrl(args.returnTo));
166
+ }
167
+ return null;
168
+ }
169
+ try {
170
+ const me = await sdk.auth.getCurrentEndUser();
171
+ const access = resolveEndUserAccess(me);
172
+ if (access.kind === "ready") {
173
+ return me;
174
+ }
175
+ if (shouldRedirect && access.shouldRedirectToSignIn) {
176
+ window.location.assign(this.buildSignInUrl(args.returnTo));
177
+ return null;
178
+ }
179
+ return me;
180
+ }
181
+ catch (error) {
182
+ const resolved = classifyBrowserRuntimeError(error);
183
+ if (resolved.shouldClearSession) {
184
+ session.clearToken();
185
+ }
186
+ if (shouldRedirect && resolved.shouldRedirectToSignIn) {
187
+ window.location.assign(this.buildSignInUrl(args.returnTo));
188
+ return null;
189
+ }
190
+ throw error;
191
+ }
192
+ },
193
+ };
194
+ }
195
+ function getCurrentLocationPath(authPath) {
196
+ if (typeof window === "undefined") {
197
+ return "/";
198
+ }
199
+ return normalizeReturnToTarget(`${window.location.pathname}${window.location.search}${window.location.hash}`, authPath);
200
+ }
201
+ function normalizeReturnToTarget(returnTo, authPath) {
202
+ const fallback = "/app";
203
+ if (typeof returnTo !== "string" || !returnTo.trim()) {
204
+ return fallback;
205
+ }
206
+ const candidate = returnTo.trim();
207
+ if (typeof window === "undefined") {
208
+ return candidate.startsWith("/") ? candidate : fallback;
209
+ }
210
+ let normalized = candidate;
211
+ if (/^https?:\/\//u.test(candidate)) {
212
+ const url = new URL(candidate, window.location.origin);
213
+ normalized = `${url.pathname}${url.search}${url.hash}`;
214
+ }
215
+ else if (!candidate.startsWith("/")) {
216
+ const url = new URL(candidate, window.location.origin);
217
+ normalized = `${url.pathname}${url.search}${url.hash}`;
218
+ }
219
+ const basePath = deriveBasePathFromAuthPath(authPath);
220
+ if (basePath !== "/" && (normalized === basePath || normalized.startsWith(`${basePath}/`))) {
221
+ const suffix = normalized.slice(basePath.length) || "/";
222
+ return suffix.startsWith("/") ? suffix : `/${suffix}`;
223
+ }
224
+ return normalized.startsWith("/") ? normalized : fallback;
225
+ }
226
+ function deriveBasePathFromAuthPath(authPath) {
227
+ const url = new URL(authPath, "http://platform.invalid");
228
+ const pathname = url.pathname.trim() || "/";
229
+ if (pathname === "/" || pathname === "/auth") {
230
+ return "/";
231
+ }
232
+ const withoutTrailingSlash = pathname.length > 1 ? pathname.replace(/\/+$/u, "") : pathname;
233
+ const authSuffix = "/auth";
234
+ if (withoutTrailingSlash === authSuffix) {
235
+ return "/";
236
+ }
237
+ if (withoutTrailingSlash.endsWith(authSuffix)) {
238
+ return withoutTrailingSlash.slice(0, -authSuffix.length) || "/";
239
+ }
240
+ return "/";
241
+ }
242
+ function withBrowserProtocol(options) {
243
+ if (options.currentProtocol) {
244
+ return options;
245
+ }
246
+ return {
247
+ ...options,
248
+ currentProtocol: getBrowserLocationProtocol()
249
+ };
250
+ }
251
+ function getBrowserLocationProtocol() {
252
+ if (typeof window === "undefined") {
253
+ return null;
254
+ }
255
+ return typeof window.location?.protocol === "string" ? window.location.protocol : null;
256
+ }