@seriousgaming/sdk 0.0.0-stage → 1.0.0-alpha.2
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/LICENSE +202 -0
- package/NOTICE +1 -0
- package/README.md +33 -2
- package/lib/build/callbacks.d.ts +998 -0
- package/lib/build/callbacks.js +32 -0
- package/lib/build/context-merge.d.ts +59 -0
- package/lib/build/context-merge.js +118 -0
- package/lib/build/document.d.ts +36 -0
- package/lib/build/document.js +8 -0
- package/lib/build/encoding.d.ts +26 -0
- package/lib/build/encoding.js +78 -0
- package/lib/build/endpoints.d.ts +421 -0
- package/lib/build/endpoints.js +46 -0
- package/lib/build/hooks.d.ts +74 -0
- package/lib/build/hooks.js +1 -0
- package/lib/build/index.d.ts +18 -0
- package/lib/build/index.js +16 -0
- package/lib/build/llm.d.ts +166 -0
- package/lib/build/llm.js +17 -0
- package/lib/build/resource-schema.d.ts +1048 -0
- package/lib/build/resource-schema.js +7 -0
- package/lib/build/scheduling.d.ts +112 -0
- package/lib/build/scheduling.js +217 -0
- package/lib/build/seed.d.ts +51 -0
- package/lib/build/seed.js +89 -0
- package/lib/build/signatures.d.ts +372 -0
- package/lib/build/signatures.js +1 -0
- package/lib/build/speech.d.ts +102 -0
- package/lib/build/speech.js +11 -0
- package/lib/build/tick-validation.d.ts +23 -0
- package/lib/build/tick-validation.js +96 -0
- package/lib/build/timer.d.ts +74 -0
- package/lib/build/timer.js +1 -0
- package/lib/build/validators.d.ts +116 -0
- package/lib/build/validators.js +1 -0
- package/lib/commands.d.ts +357 -0
- package/lib/commands.js +14 -0
- package/lib/e2e.d.ts +238 -0
- package/lib/e2e.js +248 -0
- package/lib/projection.d.ts +266 -0
- package/lib/projection.js +23 -0
- package/lib/testing/index.d.ts +13 -0
- package/lib/testing/index.js +13 -0
- package/lib/testing/logic-args.d.ts +177 -0
- package/lib/testing/logic-args.js +229 -0
- package/lib/testing/stub-services.d.ts +41 -0
- package/lib/testing/stub-services.js +176 -0
- package/lib/ui/CrossTeamDataContext.d.ts +36 -0
- package/lib/ui/CrossTeamDataContext.js +32 -0
- package/lib/ui/PresentationContext.d.ts +72 -0
- package/lib/ui/PresentationContext.js +13 -0
- package/lib/ui/PresentationWrapper.d.ts +12 -0
- package/lib/ui/PresentationWrapper.js +78 -0
- package/lib/ui/SessionUserInterfaceCallbacksContext.d.ts +3 -0
- package/lib/ui/SessionUserInterfaceCallbacksContext.js +7 -0
- package/lib/ui/SessionUserInterfaceDataContext.d.ts +103 -0
- package/lib/ui/SessionUserInterfaceDataContext.js +17 -0
- package/lib/ui/SessionUserInterfaceHookFailuresContext.d.ts +44 -0
- package/lib/ui/SessionUserInterfaceHookFailuresContext.js +15 -0
- package/lib/ui/SessionUserInterfaceHostOverlaysContext.d.ts +23 -0
- package/lib/ui/SessionUserInterfaceHostOverlaysContext.js +23 -0
- package/lib/ui/SessionUserInterfaceLocaleContext.d.ts +11 -0
- package/lib/ui/SessionUserInterfaceLocaleContext.js +13 -0
- package/lib/ui/SessionUserInterfaceMetaContext.d.ts +39 -0
- package/lib/ui/SessionUserInterfaceMetaContext.js +13 -0
- package/lib/ui/SessionUserInterfaceParticipantsContext.d.ts +12 -0
- package/lib/ui/SessionUserInterfaceParticipantsContext.js +16 -0
- package/lib/ui/SessionUserInterfaceTeamConfigurationContext.d.ts +53 -0
- package/lib/ui/SessionUserInterfaceTeamConfigurationContext.js +23 -0
- package/lib/ui/SessionUserInterfaceTeamLinksContext.d.ts +56 -0
- package/lib/ui/SessionUserInterfaceTeamLinksContext.js +12 -0
- package/lib/ui/SessionUserInterfaceTeamsContext.d.ts +13 -0
- package/lib/ui/SessionUserInterfaceTeamsContext.js +13 -0
- package/lib/ui/SessionUserInterfaceThemeContext.d.ts +9 -0
- package/lib/ui/SessionUserInterfaceThemeContext.js +7 -0
- package/lib/ui/SessionUserInterfaceThemePreferenceContext.d.ts +3 -0
- package/lib/ui/SessionUserInterfaceThemePreferenceContext.js +7 -0
- package/lib/ui/SessionUserInterfaceWalkthroughLinkContext.d.ts +42 -0
- package/lib/ui/SessionUserInterfaceWalkthroughLinkContext.js +26 -0
- package/lib/ui/SessionUserInterfaceWrapper.d.ts +8 -0
- package/lib/ui/SessionUserInterfaceWrapper.js +321 -0
- package/lib/ui/SettingsEditorCallbacksContext.d.ts +3 -0
- package/lib/ui/SettingsEditorCallbacksContext.js +7 -0
- package/lib/ui/SettingsEditorContext.d.ts +33 -0
- package/lib/ui/SettingsEditorContext.js +16 -0
- package/lib/ui/SettingsEditorLocaleContext.d.ts +13 -0
- package/lib/ui/SettingsEditorLocaleContext.js +15 -0
- package/lib/ui/SettingsEditorThemeContext.d.ts +9 -0
- package/lib/ui/SettingsEditorThemeContext.js +7 -0
- package/lib/ui/SettingsEditorThemePreferenceContext.d.ts +3 -0
- package/lib/ui/SettingsEditorThemePreferenceContext.js +7 -0
- package/lib/ui/SettingsEditorWrapper.d.ts +13 -0
- package/lib/ui/SettingsEditorWrapper.js +74 -0
- package/lib/ui/UserInterfaceCallbacksContext.d.ts +3 -0
- package/lib/ui/UserInterfaceCallbacksContext.js +7 -0
- package/lib/ui/UserInterfaceDataContext.d.ts +78 -0
- package/lib/ui/UserInterfaceDataContext.js +11 -0
- package/lib/ui/UserInterfaceLocaleContext.d.ts +13 -0
- package/lib/ui/UserInterfaceLocaleContext.js +15 -0
- package/lib/ui/UserInterfaceOwnTeamContext.d.ts +25 -0
- package/lib/ui/UserInterfaceOwnTeamContext.js +26 -0
- package/lib/ui/UserInterfaceOwnTeamJoinLinkContext.d.ts +52 -0
- package/lib/ui/UserInterfaceOwnTeamJoinLinkContext.js +13 -0
- package/lib/ui/UserInterfaceParticipantContext.d.ts +16 -0
- package/lib/ui/UserInterfaceParticipantContext.js +24 -0
- package/lib/ui/UserInterfaceParticipantsContext.d.ts +12 -0
- package/lib/ui/UserInterfaceParticipantsContext.js +13 -0
- package/lib/ui/UserInterfaceRunKindContext.d.ts +31 -0
- package/lib/ui/UserInterfaceRunKindContext.js +31 -0
- package/lib/ui/UserInterfaceTeamsContext.d.ts +12 -0
- package/lib/ui/UserInterfaceTeamsContext.js +13 -0
- package/lib/ui/UserInterfaceThemeContext.d.ts +9 -0
- package/lib/ui/UserInterfaceThemeContext.js +7 -0
- package/lib/ui/UserInterfaceThemePreferenceContext.d.ts +3 -0
- package/lib/ui/UserInterfaceThemePreferenceContext.js +7 -0
- package/lib/ui/UserInterfaceTimerContext.d.ts +10 -0
- package/lib/ui/UserInterfaceTimerContext.js +12 -0
- package/lib/ui/UserInterfaceValidationContext.d.ts +25 -0
- package/lib/ui/UserInterfaceValidationContext.js +14 -0
- package/lib/ui/UserInterfaceViewerRoleContext.d.ts +14 -0
- package/lib/ui/UserInterfaceViewerRoleContext.js +17 -0
- package/lib/ui/UserInterfaceWrapper.d.ts +8 -0
- package/lib/ui/UserInterfaceWrapper.js +219 -0
- package/lib/ui/expectedParentOrigin.d.ts +10 -0
- package/lib/ui/expectedParentOrigin.js +32 -0
- package/lib/ui/index.d.ts +50 -0
- package/lib/ui/index.js +52 -0
- package/lib/ui/internal/SurfaceGate.d.ts +19 -0
- package/lib/ui/internal/SurfaceGate.js +17 -0
- package/lib/ui/internal/SurfaceScope.d.ts +17 -0
- package/lib/ui/internal/SurfaceScope.js +16 -0
- package/lib/ui/internal/createContexts.d.ts +50 -0
- package/lib/ui/internal/createContexts.js +32 -0
- package/lib/ui/internal/document-attributes.d.ts +9 -0
- package/lib/ui/internal/document-attributes.js +87 -0
- package/lib/ui/internal/surface-timer.d.ts +3 -0
- package/lib/ui/internal/surface-timer.js +11 -0
- package/lib/ui/internal/useLatestRef.d.ts +7 -0
- package/lib/ui/internal/useLatestRef.js +11 -0
- package/lib/ui/internal/useOptimisticMerge.d.ts +19 -0
- package/lib/ui/internal/useOptimisticMerge.js +28 -0
- package/lib/ui/internal/useSurfaceControls.d.ts +52 -0
- package/lib/ui/internal/useSurfaceControls.js +19 -0
- package/lib/ui/internal/useTypedPastState.d.ts +17 -0
- package/lib/ui/internal/useTypedPastState.js +17 -0
- package/lib/ui/mutation-commit.d.ts +32 -0
- package/lib/ui/mutation-commit.js +1 -0
- package/lib/ui/mutation-outcome.d.ts +66 -0
- package/lib/ui/mutation-outcome.js +49 -0
- package/lib/ui/request-id.d.ts +18 -0
- package/lib/ui/request-id.js +44 -0
- package/lib/ui/testing.d.ts +365 -0
- package/lib/ui/testing.js +572 -0
- package/lib/ui/tick-snapshot.d.ts +28 -0
- package/lib/ui/tick-snapshot.js +34 -0
- package/lib/ui/ui-protocol.d.ts +799 -0
- package/lib/ui/ui-protocol.js +50 -0
- package/lib/ui/useAsset.d.ts +80 -0
- package/lib/ui/useAsset.js +139 -0
- package/lib/ui/useEndpointCallbacks.d.ts +31 -0
- package/lib/ui/useEndpointCallbacks.js +68 -0
- package/lib/ui/useHostChannel.d.ts +90 -0
- package/lib/ui/useHostChannel.js +338 -0
- package/lib/ui/useMutationReporter.d.ts +100 -0
- package/lib/ui/useMutationReporter.js +97 -0
- package/lib/ui/usePastState.d.ts +39 -0
- package/lib/ui/usePastState.js +63 -0
- package/lib/ui/useViewerStorage.d.ts +54 -0
- package/lib/ui/useViewerStorage.js +141 -0
- package/package.json +89 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callback interfaces for SDK components
|
|
3
|
+
*
|
|
4
|
+
* Defines the callbacks available to the engine, user interfaces, and configuration
|
|
5
|
+
* user interfaces. LLM-specific types are imported from ./llm.
|
|
6
|
+
*
|
|
7
|
+
* Asset references — every callback below that takes or returns a file
|
|
8
|
+
* identifier uses the unified asset URI scheme:
|
|
9
|
+
*
|
|
10
|
+
* `asset:<path>` — package-bundled file. The path is relative to the
|
|
11
|
+
* active scenario's `assets/` directory.
|
|
12
|
+
* `blob:<id>` — runtime-uploaded file. The id is whatever the runtime
|
|
13
|
+
* assigns when the blob was stored.
|
|
14
|
+
*
|
|
15
|
+
* Any string starting with `asset:` or `blob:` is unambiguously an asset
|
|
16
|
+
* reference. No other strings are.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Error thrown when a resource invokes a callback it did not declare in its
|
|
20
|
+
* bundle's `uses` array. Carries the offending resource identifier and the
|
|
21
|
+
* callback name so a runtime can surface both to the operator.
|
|
22
|
+
*/
|
|
23
|
+
export class UndeclaredApiUseError extends Error {
|
|
24
|
+
resourceIdentifier;
|
|
25
|
+
api;
|
|
26
|
+
constructor(resourceIdentifier, api) {
|
|
27
|
+
super(`Resource "${resourceIdentifier}" attempted to call callback "${api}" but did not declare it in its bundle's "uses" array. Add "${api}" to the bundle's uses to allow this call.`);
|
|
28
|
+
this.name = 'UndeclaredApiUseError';
|
|
29
|
+
this.resourceIdentifier = resourceIdentifier;
|
|
30
|
+
this.api = api;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The §9.5 context deep-merge, as the UI wrappers apply it to their optimistic
|
|
3
|
+
* local copy. Internal to the SDK: no entry point exports the functions here,
|
|
4
|
+
* only the `ContextUpdate` and `ContextDeletePath` types.
|
|
5
|
+
*
|
|
6
|
+
* The runtime applies the same merge from its own copy in
|
|
7
|
+
* `@seriousgaming/sdk-tools/runtime`, and
|
|
8
|
+
* `context-merge.parity.test.ts` there holds the two to one table of cases.
|
|
9
|
+
* Both must apply identical semantics or a UI sending a minimal patch sees its
|
|
10
|
+
* local view diverge from the host's until the next snapshot:
|
|
11
|
+
*
|
|
12
|
+
* - Plain objects are merged recursively
|
|
13
|
+
* - Arrays, scalars, `null`, and non-plain objects replace the base value
|
|
14
|
+
* - `__proto__`, `constructor`, and `prototype` keys are ignored (payloads
|
|
15
|
+
* cross an untrusted iframe boundary)
|
|
16
|
+
*
|
|
17
|
+
* A deep merge cannot express key deletion, so an update carries deletions
|
|
18
|
+
* beside the patch rather than inside it (see {@link ContextDeletePath} and
|
|
19
|
+
* {@link applyContextUpdate}).
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* A partial update accepted by `setData` and merged with `deepMergeContext`.
|
|
23
|
+
* Mirrors the merge semantics at the type level: object values may be given
|
|
24
|
+
* partially (they merge), while arrays and scalars must be given whole (they
|
|
25
|
+
* replace).
|
|
26
|
+
*/
|
|
27
|
+
export type ContextUpdate<T> = {
|
|
28
|
+
[K in keyof T]?: T[K] extends ReadonlyArray<unknown> ? T[K] : T[K] extends Record<string, unknown> ? ContextUpdate<T[K]> : T[K];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Where to remove a key, as a path from the root of the context.
|
|
32
|
+
*
|
|
33
|
+
* The dotted form reads best and covers almost everything, because the first
|
|
34
|
+
* two segments are a capability identifier and a variable name. Give the
|
|
35
|
+
* segments as an array where a key of your own could contain a dot — a
|
|
36
|
+
* collection keyed by something arbitrary, say — and nothing has to be
|
|
37
|
+
* escaped.
|
|
38
|
+
*
|
|
39
|
+
* ```typescript
|
|
40
|
+
* 'pinboard.Notes.01H8XY'
|
|
41
|
+
* ['pinboard', 'Notes', 'a.key.with.dots']
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export type ContextDeletePath = string | readonly string[];
|
|
45
|
+
export declare function deepMergeContext<T extends Record<string, unknown>>(base: T, patch: Record<string, unknown>): T;
|
|
46
|
+
/**
|
|
47
|
+
* The parts of `update` that differ from `current`, or undefined when nothing
|
|
48
|
+
* does. Plain objects are compared key by key; anything else by value.
|
|
49
|
+
*/
|
|
50
|
+
export declare function changedFrom(update: unknown, current: unknown): unknown;
|
|
51
|
+
/**
|
|
52
|
+
* Apply one context update: merge the patch, then remove the deleted paths.
|
|
53
|
+
*
|
|
54
|
+
* Deletions are applied after the merge so a single update can replace an
|
|
55
|
+
* entry — write the new key, drop the old — without the order of the two
|
|
56
|
+
* mattering to the caller. Every runtime applying an update MUST use this
|
|
57
|
+
* order (SPECIFICATION.md §9.5).
|
|
58
|
+
*/
|
|
59
|
+
export declare function applyContextUpdate<T extends Record<string, unknown>>(base: T, patch: Record<string, unknown>, deletes?: readonly ContextDeletePath[]): T;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The §9.5 context deep-merge, as the UI wrappers apply it to their optimistic
|
|
3
|
+
* local copy. Internal to the SDK: no entry point exports the functions here,
|
|
4
|
+
* only the `ContextUpdate` and `ContextDeletePath` types.
|
|
5
|
+
*
|
|
6
|
+
* The runtime applies the same merge from its own copy in
|
|
7
|
+
* `@seriousgaming/sdk-tools/runtime`, and
|
|
8
|
+
* `context-merge.parity.test.ts` there holds the two to one table of cases.
|
|
9
|
+
* Both must apply identical semantics or a UI sending a minimal patch sees its
|
|
10
|
+
* local view diverge from the host's until the next snapshot:
|
|
11
|
+
*
|
|
12
|
+
* - Plain objects are merged recursively
|
|
13
|
+
* - Arrays, scalars, `null`, and non-plain objects replace the base value
|
|
14
|
+
* - `__proto__`, `constructor`, and `prototype` keys are ignored (payloads
|
|
15
|
+
* cross an untrusted iframe boundary)
|
|
16
|
+
*
|
|
17
|
+
* A deep merge cannot express key deletion, so an update carries deletions
|
|
18
|
+
* beside the patch rather than inside it (see {@link ContextDeletePath} and
|
|
19
|
+
* {@link applyContextUpdate}).
|
|
20
|
+
*/
|
|
21
|
+
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
22
|
+
/**
|
|
23
|
+
* Realm-safe plain-object test.
|
|
24
|
+
*
|
|
25
|
+
* Logic is evaluated in its own V8 context, so the objects it returns
|
|
26
|
+
* carry that realm's `Object.prototype`, not this one's. Comparing against the
|
|
27
|
+
* host's `Object.prototype` alone classifies them as non-plain and replaces
|
|
28
|
+
* them, blanking sibling fields a partial patch never touched (#394). A plain
|
|
29
|
+
* object from any realm sits directly on a prototype that is itself rootless,
|
|
30
|
+
* which `Date`, `Map`, and class instances do not.
|
|
31
|
+
*/
|
|
32
|
+
function isPlainObject(value) {
|
|
33
|
+
if (value === null || typeof value !== 'object')
|
|
34
|
+
return false;
|
|
35
|
+
if (Array.isArray(value))
|
|
36
|
+
return false;
|
|
37
|
+
const proto = Object.getPrototypeOf(value);
|
|
38
|
+
if (proto === null || proto === Object.prototype)
|
|
39
|
+
return true;
|
|
40
|
+
return Object.getPrototypeOf(proto) === null;
|
|
41
|
+
}
|
|
42
|
+
export function deepMergeContext(base, patch) {
|
|
43
|
+
const result = { ...base };
|
|
44
|
+
for (const key of Object.keys(patch)) {
|
|
45
|
+
if (UNSAFE_KEYS.has(key))
|
|
46
|
+
continue;
|
|
47
|
+
const baseValue = result[key];
|
|
48
|
+
const patchValue = patch[key];
|
|
49
|
+
result[key] =
|
|
50
|
+
isPlainObject(baseValue) && isPlainObject(patchValue)
|
|
51
|
+
? deepMergeContext(baseValue, patchValue)
|
|
52
|
+
: patchValue;
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The parts of `update` that differ from `current`, or undefined when nothing
|
|
58
|
+
* does. Plain objects are compared key by key; anything else by value.
|
|
59
|
+
*/
|
|
60
|
+
export function changedFrom(update, current) {
|
|
61
|
+
if (isPlainObject(update) && isPlainObject(current)) {
|
|
62
|
+
const changed = {};
|
|
63
|
+
for (const [key, value] of Object.entries(update)) {
|
|
64
|
+
if (UNSAFE_KEYS.has(key))
|
|
65
|
+
continue;
|
|
66
|
+
const difference = changedFrom(value, current[key]);
|
|
67
|
+
if (difference !== undefined)
|
|
68
|
+
changed[key] = difference;
|
|
69
|
+
}
|
|
70
|
+
return Object.keys(changed).length > 0 ? changed : undefined;
|
|
71
|
+
}
|
|
72
|
+
return JSON.stringify(update) === JSON.stringify(current) ? undefined : update;
|
|
73
|
+
}
|
|
74
|
+
function segmentsOf(path) {
|
|
75
|
+
return typeof path === 'string' ? path.split('.') : [...path];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Remove one path from a context, cloning only the objects along the way.
|
|
79
|
+
*
|
|
80
|
+
* A path that does not resolve is not an error: two participants clearing the
|
|
81
|
+
* same note both send the delete, and the second arriving to find it already
|
|
82
|
+
* gone is the system working.
|
|
83
|
+
*/
|
|
84
|
+
function deletePath(base, path) {
|
|
85
|
+
const segments = segmentsOf(path);
|
|
86
|
+
if (segments.length === 0 || segments.some((segment) => UNSAFE_KEYS.has(segment))) {
|
|
87
|
+
return base;
|
|
88
|
+
}
|
|
89
|
+
const [head, ...rest] = segments;
|
|
90
|
+
if (!Object.prototype.hasOwnProperty.call(base, head))
|
|
91
|
+
return base;
|
|
92
|
+
if (rest.length === 0) {
|
|
93
|
+
const result = { ...base };
|
|
94
|
+
delete result[head];
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
const child = base[head];
|
|
98
|
+
if (!isPlainObject(child))
|
|
99
|
+
return base;
|
|
100
|
+
const prunedChild = deletePath(child, rest);
|
|
101
|
+
if (prunedChild === child)
|
|
102
|
+
return base;
|
|
103
|
+
return { ...base, [head]: prunedChild };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Apply one context update: merge the patch, then remove the deleted paths.
|
|
107
|
+
*
|
|
108
|
+
* Deletions are applied after the merge so a single update can replace an
|
|
109
|
+
* entry — write the new key, drop the old — without the order of the two
|
|
110
|
+
* mattering to the caller. Every runtime applying an update MUST use this
|
|
111
|
+
* order (SPECIFICATION.md §9.5).
|
|
112
|
+
*/
|
|
113
|
+
export function applyContextUpdate(base, patch, deletes) {
|
|
114
|
+
const merged = deepMergeContext(base, patch);
|
|
115
|
+
if (!deletes || deletes.length === 0)
|
|
116
|
+
return merged;
|
|
117
|
+
return deletes.reduce((context, path) => deletePath(context, path), merged);
|
|
118
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Extraction Types
|
|
3
|
+
*
|
|
4
|
+
* Provides types for extracting text content from documents (PDF, etc.)
|
|
5
|
+
* through the Serious Gaming SDK. The extracted text is suitable for
|
|
6
|
+
* passing to an LLM for further processing.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Response from extracting text from a document
|
|
10
|
+
*/
|
|
11
|
+
export interface ExtractTextResponse {
|
|
12
|
+
/**
|
|
13
|
+
* The extracted text content, typically plain text or markdown
|
|
14
|
+
*/
|
|
15
|
+
content: string;
|
|
16
|
+
/**
|
|
17
|
+
* MIME type of the source document (e.g. 'application/pdf')
|
|
18
|
+
*/
|
|
19
|
+
mimeType: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Function for extracting text from a document referenced under the unified
|
|
23
|
+
* asset URI scheme.
|
|
24
|
+
*
|
|
25
|
+
* The argument is an asset reference: either `asset:<path>` for a package-
|
|
26
|
+
* bundled file resolved against the active scenario's `assets/` directory,
|
|
27
|
+
* or `blob:<id>` for a runtime-uploaded file. The underlying parsing
|
|
28
|
+
* strategy is determined by the platform.
|
|
29
|
+
*
|
|
30
|
+
* Example:
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const fromUpload = await callbacks.extractText("blob:abc123");
|
|
33
|
+
* const fromAssets = await callbacks.extractText("asset:briefing.pdf");
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export type ExtractTextFunction = (reference: string) => Promise<ExtractTextResponse>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UTF-8 encoding helpers for author logic.
|
|
3
|
+
*
|
|
4
|
+
* The production runtime is a bare V8 isolate that exposes only the ECMAScript
|
|
5
|
+
* intrinsics — `TextEncoder`, `TextDecoder`, `Buffer`, `atob`, and `btoa` do
|
|
6
|
+
* not exist there (SPECIFICATION.md §3.2). These helpers implement UTF-8
|
|
7
|
+
* conversion in plain ECMAScript so the engine can produce bytes for `writeBlob`
|
|
8
|
+
* or read bytes from `readAsset` / `extractText` identically in the dev server
|
|
9
|
+
* and in production, with no host global. They are compiled into the author's
|
|
10
|
+
* bundle, so there is nothing for a runtime to provide.
|
|
11
|
+
*
|
|
12
|
+
* Both handle the full Unicode range, including astral-plane code points
|
|
13
|
+
* represented as surrogate pairs.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Encode a string to its UTF-8 byte sequence.
|
|
17
|
+
*
|
|
18
|
+
* A portable replacement for `new TextEncoder().encode(input)`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function encodeUtf8(input: string): Uint8Array;
|
|
21
|
+
/**
|
|
22
|
+
* Decode a UTF-8 byte sequence to a string.
|
|
23
|
+
*
|
|
24
|
+
* A portable replacement for `new TextDecoder().decode(bytes)`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function decodeUtf8(bytes: Uint8Array): string;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UTF-8 encoding helpers for author logic.
|
|
3
|
+
*
|
|
4
|
+
* The production runtime is a bare V8 isolate that exposes only the ECMAScript
|
|
5
|
+
* intrinsics — `TextEncoder`, `TextDecoder`, `Buffer`, `atob`, and `btoa` do
|
|
6
|
+
* not exist there (SPECIFICATION.md §3.2). These helpers implement UTF-8
|
|
7
|
+
* conversion in plain ECMAScript so the engine can produce bytes for `writeBlob`
|
|
8
|
+
* or read bytes from `readAsset` / `extractText` identically in the dev server
|
|
9
|
+
* and in production, with no host global. They are compiled into the author's
|
|
10
|
+
* bundle, so there is nothing for a runtime to provide.
|
|
11
|
+
*
|
|
12
|
+
* Both handle the full Unicode range, including astral-plane code points
|
|
13
|
+
* represented as surrogate pairs.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Encode a string to its UTF-8 byte sequence.
|
|
17
|
+
*
|
|
18
|
+
* A portable replacement for `new TextEncoder().encode(input)`.
|
|
19
|
+
*/
|
|
20
|
+
export function encodeUtf8(input) {
|
|
21
|
+
const bytes = [];
|
|
22
|
+
// Iterating a string with for…of yields whole code points, so surrogate
|
|
23
|
+
// pairs are already combined.
|
|
24
|
+
for (const character of input) {
|
|
25
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
26
|
+
if (codePoint < 0x80) {
|
|
27
|
+
bytes.push(codePoint);
|
|
28
|
+
}
|
|
29
|
+
else if (codePoint < 0x800) {
|
|
30
|
+
bytes.push(0xc0 | (codePoint >> 6), 0x80 | (codePoint & 0x3f));
|
|
31
|
+
}
|
|
32
|
+
else if (codePoint < 0x10000) {
|
|
33
|
+
bytes.push(0xe0 | (codePoint >> 12), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
bytes.push(0xf0 | (codePoint >> 18), 0x80 | ((codePoint >> 12) & 0x3f), 0x80 | ((codePoint >> 6) & 0x3f), 0x80 | (codePoint & 0x3f));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return Uint8Array.from(bytes);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Decode a UTF-8 byte sequence to a string.
|
|
43
|
+
*
|
|
44
|
+
* A portable replacement for `new TextDecoder().decode(bytes)`.
|
|
45
|
+
*/
|
|
46
|
+
export function decodeUtf8(bytes) {
|
|
47
|
+
let result = '';
|
|
48
|
+
let index = 0;
|
|
49
|
+
const length = bytes.length;
|
|
50
|
+
while (index < length) {
|
|
51
|
+
const byte1 = bytes[index++] ?? 0;
|
|
52
|
+
let codePoint;
|
|
53
|
+
if (byte1 < 0x80) {
|
|
54
|
+
codePoint = byte1;
|
|
55
|
+
}
|
|
56
|
+
else if ((byte1 & 0xe0) === 0xc0) {
|
|
57
|
+
const byte2 = bytes[index++] ?? 0;
|
|
58
|
+
codePoint = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
|
|
59
|
+
}
|
|
60
|
+
else if ((byte1 & 0xf0) === 0xe0) {
|
|
61
|
+
const byte2 = bytes[index++] ?? 0;
|
|
62
|
+
const byte3 = bytes[index++] ?? 0;
|
|
63
|
+
codePoint = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const byte2 = bytes[index++] ?? 0;
|
|
67
|
+
const byte3 = bytes[index++] ?? 0;
|
|
68
|
+
const byte4 = bytes[index++] ?? 0;
|
|
69
|
+
codePoint =
|
|
70
|
+
((byte1 & 0x07) << 18) |
|
|
71
|
+
((byte2 & 0x3f) << 12) |
|
|
72
|
+
((byte3 & 0x3f) << 6) |
|
|
73
|
+
(byte4 & 0x3f);
|
|
74
|
+
}
|
|
75
|
+
result += String.fromCodePoint(codePoint);
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|