@telorun/sdk 0.73.0 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bigint-json.d.ts +21 -0
- package/dist/bigint-json.d.ts.map +1 -1
- package/dist/bigint-json.js +28 -0
- package/dist/value-type.d.ts +17 -0
- package/dist/value-type.d.ts.map +1 -1
- package/dist/value-type.js +36 -5
- package/dist/value-types/entries/telo-stream.json +1 -0
- package/package.json +1 -1
- package/src/bigint-json.ts +27 -0
- package/src/value-type.ts +42 -5
- package/src/value-types/entries/telo-stream.json +1 -0
package/dist/bigint-json.d.ts
CHANGED
|
@@ -39,4 +39,25 @@ export declare function isBigIntJsonEnabled(): boolean;
|
|
|
39
39
|
* Everything that wants exact digits on the wire needs no replacer at all.
|
|
40
40
|
*/
|
|
41
41
|
export declare function bigIntAt(holder: unknown, key: string): bigint | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* A declared-integer input read as a JS number, whichever representation the
|
|
44
|
+
* call site produced.
|
|
45
|
+
*
|
|
46
|
+
* A CEL integer is an int64 — a BigInt — and the kernel normalizes a declared
|
|
47
|
+
* `type: integer` OUTPUT to that form, so one resource's result reaching another
|
|
48
|
+
* resource's input arrives as a BigInt while a YAML literal at the same slot
|
|
49
|
+
* arrives as a plain number. A controller that reads such an input with
|
|
50
|
+
* `Number.isInteger(...)` or plain arithmetic therefore works for one call site
|
|
51
|
+
* and throws `Cannot mix BigInt and other types` for the other. Inputs are
|
|
52
|
+
* deliberately NOT normalized (that would change the authoring surface of every
|
|
53
|
+
* module rather than repair a false declaration), so this is how a controller
|
|
54
|
+
* reads one.
|
|
55
|
+
*
|
|
56
|
+
* Returns `undefined` for anything that is not an integer in either
|
|
57
|
+
* representation — including a BigInt too large for a double, since silently
|
|
58
|
+
* rounding it would be the precision loss int64 support exists to remove — so a
|
|
59
|
+
* caller's own "must be a non-negative integer" check still rejects what it
|
|
60
|
+
* should.
|
|
61
|
+
*/
|
|
62
|
+
export declare function integerInput(value: unknown): number | undefined;
|
|
42
63
|
//# sourceMappingURL=bigint-json.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bigint-json.d.ts","sourceRoot":"","sources":["../src/bigint-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;uCAGuC;AACvC,eAAO,MAAM,yBAAyB,QAAgB,CAAC;AAEvD,oFAAoF;AACpF,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE"}
|
|
1
|
+
{"version":3,"file":"bigint-json.d.ts","sourceRoot":"","sources":["../src/bigint-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;uCAGuC;AACvC,eAAO,MAAM,yBAAyB,QAAgB,CAAC;AAEvD,oFAAoF;AACpF,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK/D"}
|
package/dist/bigint-json.js
CHANGED
|
@@ -45,3 +45,31 @@ export function bigIntAt(holder, key) {
|
|
|
45
45
|
const source = holder?.[key];
|
|
46
46
|
return typeof source === "bigint" ? source : undefined;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* A declared-integer input read as a JS number, whichever representation the
|
|
50
|
+
* call site produced.
|
|
51
|
+
*
|
|
52
|
+
* A CEL integer is an int64 — a BigInt — and the kernel normalizes a declared
|
|
53
|
+
* `type: integer` OUTPUT to that form, so one resource's result reaching another
|
|
54
|
+
* resource's input arrives as a BigInt while a YAML literal at the same slot
|
|
55
|
+
* arrives as a plain number. A controller that reads such an input with
|
|
56
|
+
* `Number.isInteger(...)` or plain arithmetic therefore works for one call site
|
|
57
|
+
* and throws `Cannot mix BigInt and other types` for the other. Inputs are
|
|
58
|
+
* deliberately NOT normalized (that would change the authoring surface of every
|
|
59
|
+
* module rather than repair a false declaration), so this is how a controller
|
|
60
|
+
* reads one.
|
|
61
|
+
*
|
|
62
|
+
* Returns `undefined` for anything that is not an integer in either
|
|
63
|
+
* representation — including a BigInt too large for a double, since silently
|
|
64
|
+
* rounding it would be the precision loss int64 support exists to remove — so a
|
|
65
|
+
* caller's own "must be a non-negative integer" check still rejects what it
|
|
66
|
+
* should.
|
|
67
|
+
*/
|
|
68
|
+
export function integerInput(value) {
|
|
69
|
+
if (typeof value === "number")
|
|
70
|
+
return Number.isInteger(value) ? value : undefined;
|
|
71
|
+
if (typeof value !== "bigint")
|
|
72
|
+
return undefined;
|
|
73
|
+
const asNumber = Number(value);
|
|
74
|
+
return Number.isSafeInteger(asNumber) ? asNumber : undefined;
|
|
75
|
+
}
|
package/dist/value-type.d.ts
CHANGED
|
@@ -38,6 +38,12 @@ export type ValueTypeRepresentation = "json" | "instance";
|
|
|
38
38
|
* second parameter can be added without a migration. */
|
|
39
39
|
export interface ValueTypeParameter {
|
|
40
40
|
readonly name: string;
|
|
41
|
+
/** This parameter's argument is what ITERATING a value of the type yields.
|
|
42
|
+
* Declared here so "what is the element of this collection" is answered by
|
|
43
|
+
* the vocabulary rather than by a consumer that knows one type's name — the
|
|
44
|
+
* same reason `live` is a field and not a check against `Telo.Stream`. At
|
|
45
|
+
* most one parameter per entry may carry it. */
|
|
46
|
+
readonly element?: boolean;
|
|
41
47
|
readonly description?: string;
|
|
42
48
|
}
|
|
43
49
|
/** One value type, exactly as its entry file declares it. */
|
|
@@ -124,6 +130,17 @@ export declare function isLiveSlot(schema: unknown): boolean;
|
|
|
124
130
|
/** True when the node declares a type represented as a runtime instance —
|
|
125
131
|
* the values no manifest literal can ever be. */
|
|
126
132
|
export declare function isInstanceSlot(schema: unknown): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* The schema of what iterating a value at this slot yields, or undefined when
|
|
135
|
+
* the slot declares no value type, or one with no element parameter.
|
|
136
|
+
*
|
|
137
|
+
* The whole point of reading it from the entry is that no consumer names a type:
|
|
138
|
+
* a future iterable value type is covered by declaring `element` on its own
|
|
139
|
+
* parameter, with nothing to change here or in the analyzer. An element
|
|
140
|
+
* parameter left unsupplied means *any*, exactly as every other omitted argument
|
|
141
|
+
* does, so an unparameterized use degrades to permissive rather than to nothing.
|
|
142
|
+
*/
|
|
143
|
+
export declare function elementSchemaOf(schema: unknown): unknown | undefined;
|
|
127
144
|
/** The binding row for a schema node's declared type, or undefined when it
|
|
128
145
|
* declares none / declares a `json` one. */
|
|
129
146
|
export declare function bindingOf(schema: unknown): ValueTypeBinding | undefined;
|
package/dist/value-type.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"value-type.d.ts","sourceRoot":"","sources":["../src/value-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAKH,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC;;;;;4EAK4E;AAC5E,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,UAAU,CAAC;AAE1D;;;yDAGyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,uBAAuB,CAAC;IACjD,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;iFAC6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;yCAEyC;AACzC,MAAM,WAAW,gBAAgB;IAC/B;oEACgE;IAChE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;IAC/B,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;qDAGiD;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;CACtC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAG1E,CAAC;
|
|
1
|
+
{"version":3,"file":"value-type.d.ts","sourceRoot":"","sources":["../src/value-type.ts"],"names":[],"mappings":"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"}
|
package/dist/value-type.js
CHANGED
|
@@ -80,20 +80,34 @@ function readParameters(file, raw) {
|
|
|
80
80
|
return [];
|
|
81
81
|
if (!Array.isArray(raw))
|
|
82
82
|
throw new ValueTypeEntryError(file, "'parameters' must be a sequence");
|
|
83
|
-
|
|
83
|
+
const params = raw.map((entry, i) => {
|
|
84
84
|
if (!isPlainObject(entry)) {
|
|
85
85
|
throw new ValueTypeEntryError(file, `parameters[${i}] must be a mapping`);
|
|
86
86
|
}
|
|
87
87
|
for (const key of Object.keys(entry)) {
|
|
88
|
-
if (key !== "name" && key !== "description") {
|
|
88
|
+
if (key !== "name" && key !== "description" && key !== "element") {
|
|
89
89
|
throw new ValueTypeEntryError(file, `parameters[${i}] has no key '${key}'`);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
+
if (entry.element !== undefined && typeof entry.element !== "boolean") {
|
|
93
|
+
throw new ValueTypeEntryError(file, `parameters[${i}].element must be a boolean when present`);
|
|
94
|
+
}
|
|
92
95
|
const name = requireString(file, entry, "name");
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
return {
|
|
97
|
+
name,
|
|
98
|
+
...(entry.element === true ? { element: true } : {}),
|
|
99
|
+
...(entry.description === undefined
|
|
100
|
+
? {}
|
|
101
|
+
: { description: requireString(file, entry, "description") }),
|
|
102
|
+
};
|
|
96
103
|
});
|
|
104
|
+
// Two element parameters would make "the element of this value" ambiguous, and
|
|
105
|
+
// the reader is the only place that can refuse it — every consumer takes the
|
|
106
|
+
// first match and would silently pick one.
|
|
107
|
+
if (params.filter((p) => p.element).length > 1) {
|
|
108
|
+
throw new ValueTypeEntryError(file, "at most one parameter may declare 'element'");
|
|
109
|
+
}
|
|
110
|
+
return params;
|
|
97
111
|
}
|
|
98
112
|
/**
|
|
99
113
|
* Read one entry file's parsed data.
|
|
@@ -242,6 +256,23 @@ export function isLiveSlot(schema) {
|
|
|
242
256
|
export function isInstanceSlot(schema) {
|
|
243
257
|
return valueTypeOf(schema)?.representation === "instance";
|
|
244
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* The schema of what iterating a value at this slot yields, or undefined when
|
|
261
|
+
* the slot declares no value type, or one with no element parameter.
|
|
262
|
+
*
|
|
263
|
+
* The whole point of reading it from the entry is that no consumer names a type:
|
|
264
|
+
* a future iterable value type is covered by declaring `element` on its own
|
|
265
|
+
* parameter, with nothing to change here or in the analyzer. An element
|
|
266
|
+
* parameter left unsupplied means *any*, exactly as every other omitted argument
|
|
267
|
+
* does, so an unparameterized use degrades to permissive rather than to nothing.
|
|
268
|
+
*/
|
|
269
|
+
export function elementSchemaOf(schema) {
|
|
270
|
+
const slot = readValueTypeSlot(schema);
|
|
271
|
+
const parameter = slot?.entry?.parameters.find((p) => p.element);
|
|
272
|
+
if (!parameter)
|
|
273
|
+
return undefined;
|
|
274
|
+
return slot.args[parameter.name] ?? {};
|
|
275
|
+
}
|
|
245
276
|
/** The binding row for a schema node's declared type, or undefined when it
|
|
246
277
|
* declares none / declares a `json` one. */
|
|
247
278
|
export function bindingOf(schema) {
|
package/package.json
CHANGED
package/src/bigint-json.ts
CHANGED
|
@@ -49,3 +49,30 @@ export function bigIntAt(holder: unknown, key: string): bigint | undefined {
|
|
|
49
49
|
const source = (holder as Record<string, unknown> | null | undefined)?.[key];
|
|
50
50
|
return typeof source === "bigint" ? source : undefined;
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A declared-integer input read as a JS number, whichever representation the
|
|
55
|
+
* call site produced.
|
|
56
|
+
*
|
|
57
|
+
* A CEL integer is an int64 — a BigInt — and the kernel normalizes a declared
|
|
58
|
+
* `type: integer` OUTPUT to that form, so one resource's result reaching another
|
|
59
|
+
* resource's input arrives as a BigInt while a YAML literal at the same slot
|
|
60
|
+
* arrives as a plain number. A controller that reads such an input with
|
|
61
|
+
* `Number.isInteger(...)` or plain arithmetic therefore works for one call site
|
|
62
|
+
* and throws `Cannot mix BigInt and other types` for the other. Inputs are
|
|
63
|
+
* deliberately NOT normalized (that would change the authoring surface of every
|
|
64
|
+
* module rather than repair a false declaration), so this is how a controller
|
|
65
|
+
* reads one.
|
|
66
|
+
*
|
|
67
|
+
* Returns `undefined` for anything that is not an integer in either
|
|
68
|
+
* representation — including a BigInt too large for a double, since silently
|
|
69
|
+
* rounding it would be the precision loss int64 support exists to remove — so a
|
|
70
|
+
* caller's own "must be a non-negative integer" check still rejects what it
|
|
71
|
+
* should.
|
|
72
|
+
*/
|
|
73
|
+
export function integerInput(value: unknown): number | undefined {
|
|
74
|
+
if (typeof value === "number") return Number.isInteger(value) ? value : undefined;
|
|
75
|
+
if (typeof value !== "bigint") return undefined;
|
|
76
|
+
const asNumber = Number(value);
|
|
77
|
+
return Number.isSafeInteger(asNumber) ? asNumber : undefined;
|
|
78
|
+
}
|
package/src/value-type.ts
CHANGED
|
@@ -44,6 +44,12 @@ export type ValueTypeRepresentation = "json" | "instance";
|
|
|
44
44
|
* second parameter can be added without a migration. */
|
|
45
45
|
export interface ValueTypeParameter {
|
|
46
46
|
readonly name: string;
|
|
47
|
+
/** This parameter's argument is what ITERATING a value of the type yields.
|
|
48
|
+
* Declared here so "what is the element of this collection" is answered by
|
|
49
|
+
* the vocabulary rather than by a consumer that knows one type's name — the
|
|
50
|
+
* same reason `live` is a field and not a check against `Telo.Stream`. At
|
|
51
|
+
* most one parameter per entry may carry it. */
|
|
52
|
+
readonly element?: boolean;
|
|
47
53
|
readonly description?: string;
|
|
48
54
|
}
|
|
49
55
|
|
|
@@ -136,20 +142,34 @@ function requireString(file: string, node: Record<string, unknown>, key: string)
|
|
|
136
142
|
function readParameters(file: string, raw: unknown): ValueTypeParameter[] {
|
|
137
143
|
if (raw === undefined) return [];
|
|
138
144
|
if (!Array.isArray(raw)) throw new ValueTypeEntryError(file, "'parameters' must be a sequence");
|
|
139
|
-
|
|
145
|
+
const params = raw.map((entry, i) => {
|
|
140
146
|
if (!isPlainObject(entry)) {
|
|
141
147
|
throw new ValueTypeEntryError(file, `parameters[${i}] must be a mapping`);
|
|
142
148
|
}
|
|
143
149
|
for (const key of Object.keys(entry)) {
|
|
144
|
-
if (key !== "name" && key !== "description") {
|
|
150
|
+
if (key !== "name" && key !== "description" && key !== "element") {
|
|
145
151
|
throw new ValueTypeEntryError(file, `parameters[${i}] has no key '${key}'`);
|
|
146
152
|
}
|
|
147
153
|
}
|
|
154
|
+
if (entry.element !== undefined && typeof entry.element !== "boolean") {
|
|
155
|
+
throw new ValueTypeEntryError(file, `parameters[${i}].element must be a boolean when present`);
|
|
156
|
+
}
|
|
148
157
|
const name = requireString(file, entry, "name");
|
|
149
|
-
return
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
return {
|
|
159
|
+
name,
|
|
160
|
+
...(entry.element === true ? { element: true as const } : {}),
|
|
161
|
+
...(entry.description === undefined
|
|
162
|
+
? {}
|
|
163
|
+
: { description: requireString(file, entry, "description") }),
|
|
164
|
+
};
|
|
152
165
|
});
|
|
166
|
+
// Two element parameters would make "the element of this value" ambiguous, and
|
|
167
|
+
// the reader is the only place that can refuse it — every consumer takes the
|
|
168
|
+
// first match and would silently pick one.
|
|
169
|
+
if (params.filter((p) => p.element).length > 1) {
|
|
170
|
+
throw new ValueTypeEntryError(file, "at most one parameter may declare 'element'");
|
|
171
|
+
}
|
|
172
|
+
return params;
|
|
153
173
|
}
|
|
154
174
|
|
|
155
175
|
/**
|
|
@@ -334,6 +354,23 @@ export function isInstanceSlot(schema: unknown): boolean {
|
|
|
334
354
|
return valueTypeOf(schema)?.representation === "instance";
|
|
335
355
|
}
|
|
336
356
|
|
|
357
|
+
/**
|
|
358
|
+
* The schema of what iterating a value at this slot yields, or undefined when
|
|
359
|
+
* the slot declares no value type, or one with no element parameter.
|
|
360
|
+
*
|
|
361
|
+
* The whole point of reading it from the entry is that no consumer names a type:
|
|
362
|
+
* a future iterable value type is covered by declaring `element` on its own
|
|
363
|
+
* parameter, with nothing to change here or in the analyzer. An element
|
|
364
|
+
* parameter left unsupplied means *any*, exactly as every other omitted argument
|
|
365
|
+
* does, so an unparameterized use degrades to permissive rather than to nothing.
|
|
366
|
+
*/
|
|
367
|
+
export function elementSchemaOf(schema: unknown): unknown | undefined {
|
|
368
|
+
const slot = readValueTypeSlot(schema);
|
|
369
|
+
const parameter = slot?.entry?.parameters.find((p) => p.element);
|
|
370
|
+
if (!parameter) return undefined;
|
|
371
|
+
return slot!.args[parameter.name] ?? {};
|
|
372
|
+
}
|
|
373
|
+
|
|
337
374
|
/** The binding row for a schema node's declared type, or undefined when it
|
|
338
375
|
* declares none / declares a `json` one. */
|
|
339
376
|
export function bindingOf(schema: unknown): ValueTypeBinding | undefined {
|