@rcrsr/rill 0.16.0 → 0.17.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/README.md +37 -21
- package/dist/ext/crypto/index.d.ts +3 -3
- package/dist/ext/crypto/index.js +61 -58
- package/dist/ext/exec/index.d.ts +3 -3
- package/dist/ext/exec/index.js +14 -8
- package/dist/ext/fetch/index.d.ts +3 -3
- package/dist/ext/fetch/index.js +16 -11
- package/dist/ext/fs/index.d.ts +3 -3
- package/dist/ext/fs/index.js +242 -239
- package/dist/ext/kv/index.d.ts +3 -3
- package/dist/ext/kv/index.js +197 -195
- package/dist/ext/kv/store.js +2 -1
- package/dist/ext-parse-bridge.d.ts +10 -0
- package/dist/ext-parse-bridge.js +10 -0
- package/dist/generated/introspection-data.d.ts +1 -1
- package/dist/generated/introspection-data.js +385 -296
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +2 -2
- package/dist/index.d.ts +15 -4
- package/dist/index.js +14 -5
- package/dist/parser/parser-types.js +12 -0
- package/dist/parser/parser-use.js +7 -1
- package/dist/runtime/core/callable.d.ts +20 -8
- package/dist/runtime/core/callable.js +63 -23
- package/dist/runtime/core/context.d.ts +0 -11
- package/dist/runtime/core/context.js +76 -75
- package/dist/runtime/core/eval/index.d.ts +2 -2
- package/dist/runtime/core/eval/index.js +11 -0
- package/dist/runtime/core/eval/mixins/closures.js +15 -15
- package/dist/runtime/core/eval/mixins/conversion.js +51 -110
- package/dist/runtime/core/eval/mixins/core.js +2 -2
- package/dist/runtime/core/eval/mixins/expressions.js +35 -27
- package/dist/runtime/core/eval/mixins/literals.js +3 -3
- package/dist/runtime/core/eval/mixins/types.js +44 -54
- package/dist/runtime/core/eval/mixins/variables.js +10 -8
- package/dist/runtime/core/field-descriptor.d.ts +3 -3
- package/dist/runtime/core/field-descriptor.js +2 -1
- package/dist/runtime/core/introspection.js +6 -6
- package/dist/runtime/core/markers.d.ts +12 -0
- package/dist/runtime/core/markers.js +7 -0
- package/dist/runtime/core/type-registrations.d.ts +136 -0
- package/dist/runtime/core/type-registrations.js +749 -0
- package/dist/runtime/core/type-structures.d.ts +128 -0
- package/dist/runtime/core/type-structures.js +12 -0
- package/dist/runtime/core/types.d.ts +15 -3
- package/dist/runtime/core/values.d.ts +62 -153
- package/dist/runtime/core/values.js +308 -524
- package/dist/runtime/ext/builtins.js +83 -64
- package/dist/runtime/ext/extensions.d.ts +30 -124
- package/dist/runtime/ext/extensions.js +0 -93
- package/dist/runtime/ext/test-context.d.ts +28 -0
- package/dist/runtime/ext/test-context.js +154 -0
- package/dist/runtime/index.d.ts +22 -8
- package/dist/runtime/index.js +18 -4
- package/dist/signature-parser.d.ts +2 -2
- package/dist/signature-parser.js +14 -14
- package/package.json +1 -1
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
import { callable, isCallable, isDict } from '../core/callable.js';
|
|
10
10
|
import { RuntimeError } from '../../types.js';
|
|
11
11
|
import { parseSignatureRegistration } from '../../signature-parser.js';
|
|
12
|
-
import { anyTypeValue, deepEquals, formatValue, inferType, isEmpty, isRillIterator, isVector, rillTypeToTypeValue,
|
|
12
|
+
import { anyTypeValue, deepEquals, formatValue, inferType, isEmpty, isRillIterator, isVector, rillTypeToTypeValue, serializeValue, } from '../core/values.js';
|
|
13
13
|
import { invokeCallable } from '../core/eval/index.js';
|
|
14
|
+
import { populateBuiltinMethods } from '../core/type-registrations.js';
|
|
14
15
|
// ============================================================
|
|
15
16
|
// ITERATOR HELPERS
|
|
16
17
|
// ============================================================
|
|
@@ -70,7 +71,7 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
70
71
|
params: [
|
|
71
72
|
{
|
|
72
73
|
name: 'value',
|
|
73
|
-
type: {
|
|
74
|
+
type: { kind: 'any' },
|
|
74
75
|
defaultValue: undefined,
|
|
75
76
|
annotations: {},
|
|
76
77
|
},
|
|
@@ -83,7 +84,7 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
83
84
|
params: [
|
|
84
85
|
{
|
|
85
86
|
name: 'message',
|
|
86
|
-
type: {
|
|
87
|
+
type: { kind: 'any' },
|
|
87
88
|
defaultValue: undefined,
|
|
88
89
|
annotations: {},
|
|
89
90
|
},
|
|
@@ -103,16 +104,16 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
103
104
|
params: [
|
|
104
105
|
{
|
|
105
106
|
name: 'value',
|
|
106
|
-
type: {
|
|
107
|
+
type: { kind: 'any' },
|
|
107
108
|
defaultValue: undefined,
|
|
108
109
|
annotations: {},
|
|
109
110
|
},
|
|
110
111
|
],
|
|
111
|
-
returnType: rillTypeToTypeValue({
|
|
112
|
+
returnType: rillTypeToTypeValue({ kind: 'string' }),
|
|
112
113
|
fn: (args, _ctx, location) => {
|
|
113
114
|
const value = args['value'] ?? null;
|
|
114
115
|
try {
|
|
115
|
-
const jsonValue =
|
|
116
|
+
const jsonValue = serializeValue(value);
|
|
116
117
|
return JSON.stringify(jsonValue);
|
|
117
118
|
}
|
|
118
119
|
catch (err) {
|
|
@@ -135,14 +136,14 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
135
136
|
{
|
|
136
137
|
name: 'items',
|
|
137
138
|
type: {
|
|
138
|
-
|
|
139
|
-
members: [{
|
|
139
|
+
kind: 'union',
|
|
140
|
+
members: [{ kind: 'list' }, { kind: 'dict' }, { kind: 'string' }],
|
|
140
141
|
},
|
|
141
142
|
defaultValue: undefined,
|
|
142
143
|
annotations: {},
|
|
143
144
|
},
|
|
144
145
|
],
|
|
145
|
-
returnType: rillTypeToTypeValue({
|
|
146
|
+
returnType: rillTypeToTypeValue({ kind: 'list' }),
|
|
146
147
|
fn: (args) => {
|
|
147
148
|
const input = args['items'] ?? null;
|
|
148
149
|
if (Array.isArray(input)) {
|
|
@@ -167,19 +168,19 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
167
168
|
params: [
|
|
168
169
|
{
|
|
169
170
|
name: 'start',
|
|
170
|
-
type: {
|
|
171
|
+
type: { kind: 'number' },
|
|
171
172
|
defaultValue: undefined,
|
|
172
173
|
annotations: {},
|
|
173
174
|
},
|
|
174
175
|
{
|
|
175
176
|
name: 'stop',
|
|
176
|
-
type: {
|
|
177
|
+
type: { kind: 'number' },
|
|
177
178
|
defaultValue: undefined,
|
|
178
179
|
annotations: {},
|
|
179
180
|
},
|
|
180
181
|
{
|
|
181
182
|
name: 'step',
|
|
182
|
-
type: {
|
|
183
|
+
type: { kind: 'number' },
|
|
183
184
|
defaultValue: 1,
|
|
184
185
|
annotations: {},
|
|
185
186
|
},
|
|
@@ -217,13 +218,13 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
217
218
|
params: [
|
|
218
219
|
{
|
|
219
220
|
name: 'value',
|
|
220
|
-
type: {
|
|
221
|
+
type: { kind: 'any' },
|
|
221
222
|
defaultValue: undefined,
|
|
222
223
|
annotations: {},
|
|
223
224
|
},
|
|
224
225
|
{
|
|
225
226
|
name: 'count',
|
|
226
|
-
type: {
|
|
227
|
+
type: { kind: 'number' },
|
|
227
228
|
defaultValue: undefined,
|
|
228
229
|
annotations: {},
|
|
229
230
|
},
|
|
@@ -262,13 +263,13 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
262
263
|
params: [
|
|
263
264
|
{
|
|
264
265
|
name: 'value',
|
|
265
|
-
type: {
|
|
266
|
+
type: { kind: 'any' },
|
|
266
267
|
defaultValue: undefined,
|
|
267
268
|
annotations: {},
|
|
268
269
|
},
|
|
269
270
|
{
|
|
270
271
|
name: 'transform',
|
|
271
|
-
type: {
|
|
272
|
+
type: { kind: 'any' },
|
|
272
273
|
defaultValue: undefined,
|
|
273
274
|
annotations: {},
|
|
274
275
|
},
|
|
@@ -311,20 +312,10 @@ export const BUILTIN_FUNCTIONS = {
|
|
|
311
312
|
// ============================================================
|
|
312
313
|
// BUILT-IN METHODS
|
|
313
314
|
// ============================================================
|
|
314
|
-
/** Factory for comparison methods (lt, gt, le, ge) */
|
|
315
|
-
function createComparisonMethod(compare) {
|
|
316
|
-
return (receiver, args) => {
|
|
317
|
-
const arg = args[0];
|
|
318
|
-
if (typeof receiver === 'number' && typeof arg === 'number') {
|
|
319
|
-
return compare(receiver, arg);
|
|
320
|
-
}
|
|
321
|
-
return compare(formatValue(receiver), formatValue(arg ?? ''));
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
315
|
/** Receiver param prepended to every method's param list */
|
|
325
316
|
const RECEIVER_PARAM = {
|
|
326
317
|
name: 'receiver',
|
|
327
|
-
type: {
|
|
318
|
+
type: { kind: 'any' },
|
|
328
319
|
defaultValue: undefined,
|
|
329
320
|
annotations: {},
|
|
330
321
|
};
|
|
@@ -337,7 +328,7 @@ const RECEIVER_PARAM = {
|
|
|
337
328
|
*
|
|
338
329
|
* EC-4: Receiver missing from record raises RILL-R044.
|
|
339
330
|
*/
|
|
340
|
-
function buildMethodEntry(name, signature, method) {
|
|
331
|
+
function buildMethodEntry(name, signature, method, skipReceiverValidation) {
|
|
341
332
|
const parsed = parseSignatureRegistration(signature, name);
|
|
342
333
|
const methodParams = parsed.params;
|
|
343
334
|
return {
|
|
@@ -361,6 +352,7 @@ function buildMethodEntry(name, signature, method) {
|
|
|
361
352
|
returnType: parsed.returnType !== undefined
|
|
362
353
|
? rillTypeToTypeValue(parsed.returnType)
|
|
363
354
|
: anyTypeValue,
|
|
355
|
+
...(skipReceiverValidation ? { skipReceiverValidation: true } : {}),
|
|
364
356
|
};
|
|
365
357
|
}
|
|
366
358
|
export const BUILTIN_METHODS = {
|
|
@@ -552,10 +544,34 @@ const mPadEnd = (receiver, args) => {
|
|
|
552
544
|
const mEq = (receiver, args) => deepEquals(receiver, args[0] ?? null);
|
|
553
545
|
/** Inequality check (deep structural comparison) */
|
|
554
546
|
const mNe = (receiver, args) => !deepEquals(receiver, args[0] ?? null);
|
|
555
|
-
|
|
556
|
-
const
|
|
557
|
-
const
|
|
558
|
-
|
|
547
|
+
/** Less-than comparison (number or string) */
|
|
548
|
+
const mLt = (receiver, args) => {
|
|
549
|
+
const arg = args[0];
|
|
550
|
+
if (typeof receiver === 'number' && typeof arg === 'number')
|
|
551
|
+
return receiver < arg;
|
|
552
|
+
return formatValue(receiver) < formatValue(arg ?? '');
|
|
553
|
+
};
|
|
554
|
+
/** Greater-than comparison (number or string) */
|
|
555
|
+
const mGt = (receiver, args) => {
|
|
556
|
+
const arg = args[0];
|
|
557
|
+
if (typeof receiver === 'number' && typeof arg === 'number')
|
|
558
|
+
return receiver > arg;
|
|
559
|
+
return formatValue(receiver) > formatValue(arg ?? '');
|
|
560
|
+
};
|
|
561
|
+
/** Less-than-or-equal comparison (number or string) */
|
|
562
|
+
const mLe = (receiver, args) => {
|
|
563
|
+
const arg = args[0];
|
|
564
|
+
if (typeof receiver === 'number' && typeof arg === 'number')
|
|
565
|
+
return receiver <= arg;
|
|
566
|
+
return formatValue(receiver) <= formatValue(arg ?? '');
|
|
567
|
+
};
|
|
568
|
+
/** Greater-than-or-equal comparison (number or string) */
|
|
569
|
+
const mGe = (receiver, args) => {
|
|
570
|
+
const arg = args[0];
|
|
571
|
+
if (typeof receiver === 'number' && typeof arg === 'number')
|
|
572
|
+
return receiver >= arg;
|
|
573
|
+
return formatValue(receiver) >= formatValue(arg ?? '');
|
|
574
|
+
};
|
|
559
575
|
/** Get all keys of a dict as a list */
|
|
560
576
|
const mKeys = (receiver) => isDict(receiver) ? Object.keys(receiver) : [];
|
|
561
577
|
/** Get all values of a dict as a list */
|
|
@@ -757,10 +773,10 @@ const SIG_CMP = '|other: any|:bool';
|
|
|
757
773
|
BUILTIN_METHODS.string = Object.freeze({
|
|
758
774
|
len: buildMethodEntry('len', SIG_LEN, mLen),
|
|
759
775
|
trim: buildMethodEntry('trim', '||:string', mTrim),
|
|
760
|
-
head: buildMethodEntry('head', SIG_HEAD, mHead),
|
|
761
|
-
tail: buildMethodEntry('tail', SIG_TAIL, mTail),
|
|
762
|
-
first: buildMethodEntry('first', SIG_FIRST, mFirst),
|
|
763
|
-
at: buildMethodEntry('at', SIG_AT, mAt),
|
|
776
|
+
head: buildMethodEntry('head', SIG_HEAD, mHead, true),
|
|
777
|
+
tail: buildMethodEntry('tail', SIG_TAIL, mTail, true),
|
|
778
|
+
first: buildMethodEntry('first', SIG_FIRST, mFirst, true),
|
|
779
|
+
at: buildMethodEntry('at', SIG_AT, mAt, true),
|
|
764
780
|
split: buildMethodEntry('split', '|separator: string = "\\n"|:list', mSplit),
|
|
765
781
|
lines: buildMethodEntry('lines', '||:list', mLines),
|
|
766
782
|
empty: buildMethodEntry('empty', SIG_EMPTY, mEmpty),
|
|
@@ -777,8 +793,8 @@ BUILTIN_METHODS.string = Object.freeze({
|
|
|
777
793
|
repeat: buildMethodEntry('repeat', '|count: number|:string', mRepeat),
|
|
778
794
|
pad_start: buildMethodEntry('pad_start', '|length: number, fill: string = " "|:string', mPadStart),
|
|
779
795
|
pad_end: buildMethodEntry('pad_end', '|length: number, fill: string = " "|:string', mPadEnd),
|
|
780
|
-
eq: buildMethodEntry('eq', SIG_EQ, mEq),
|
|
781
|
-
ne: buildMethodEntry('ne', SIG_NE, mNe),
|
|
796
|
+
eq: buildMethodEntry('eq', SIG_EQ, mEq, true),
|
|
797
|
+
ne: buildMethodEntry('ne', SIG_NE, mNe, true),
|
|
782
798
|
lt: buildMethodEntry('lt', SIG_CMP, mLt),
|
|
783
799
|
gt: buildMethodEntry('gt', SIG_CMP, mGt),
|
|
784
800
|
le: buildMethodEntry('le', SIG_CMP, mLe),
|
|
@@ -786,32 +802,32 @@ BUILTIN_METHODS.string = Object.freeze({
|
|
|
786
802
|
});
|
|
787
803
|
BUILTIN_METHODS.list = Object.freeze({
|
|
788
804
|
len: buildMethodEntry('len', SIG_LEN, mLen),
|
|
789
|
-
head: buildMethodEntry('head', SIG_HEAD, mHead),
|
|
790
|
-
tail: buildMethodEntry('tail', SIG_TAIL, mTail),
|
|
791
|
-
first: buildMethodEntry('first', SIG_FIRST, mFirst),
|
|
792
|
-
at: buildMethodEntry('at', SIG_AT, mAt),
|
|
805
|
+
head: buildMethodEntry('head', SIG_HEAD, mHead, true),
|
|
806
|
+
tail: buildMethodEntry('tail', SIG_TAIL, mTail, true),
|
|
807
|
+
first: buildMethodEntry('first', SIG_FIRST, mFirst, true),
|
|
808
|
+
at: buildMethodEntry('at', SIG_AT, mAt, true),
|
|
793
809
|
join: buildMethodEntry('join', '|separator: string = ","|:string', mJoin),
|
|
794
810
|
empty: buildMethodEntry('empty', SIG_EMPTY, mEmpty),
|
|
795
|
-
eq: buildMethodEntry('eq', SIG_EQ, mEq),
|
|
796
|
-
ne: buildMethodEntry('ne', SIG_NE, mNe),
|
|
797
|
-
has: buildMethodEntry('has', '|value: any|:bool', mHas),
|
|
798
|
-
has_any: buildMethodEntry('has_any', '|candidates: list|:bool', mHasAny),
|
|
799
|
-
has_all: buildMethodEntry('has_all', '|candidates: list|:bool', mHasAll),
|
|
811
|
+
eq: buildMethodEntry('eq', SIG_EQ, mEq, true),
|
|
812
|
+
ne: buildMethodEntry('ne', SIG_NE, mNe, true),
|
|
813
|
+
has: buildMethodEntry('has', '|value: any|:bool', mHas, true),
|
|
814
|
+
has_any: buildMethodEntry('has_any', '|candidates: list|:bool', mHasAny, true),
|
|
815
|
+
has_all: buildMethodEntry('has_all', '|candidates: list|:bool', mHasAll, true),
|
|
800
816
|
});
|
|
801
817
|
BUILTIN_METHODS.dict = Object.freeze({
|
|
802
818
|
len: buildMethodEntry('len', SIG_LEN, mLen),
|
|
803
|
-
first: buildMethodEntry('first', SIG_FIRST, mFirst),
|
|
819
|
+
first: buildMethodEntry('first', SIG_FIRST, mFirst, true),
|
|
804
820
|
empty: buildMethodEntry('empty', SIG_EMPTY, mEmpty),
|
|
805
|
-
eq: buildMethodEntry('eq', SIG_EQ, mEq),
|
|
806
|
-
ne: buildMethodEntry('ne', SIG_NE, mNe),
|
|
807
|
-
keys: buildMethodEntry('keys', '||:list', mKeys),
|
|
808
|
-
values: buildMethodEntry('values', '||:list', mValues),
|
|
809
|
-
entries: buildMethodEntry('entries', '||:list', mEntries),
|
|
821
|
+
eq: buildMethodEntry('eq', SIG_EQ, mEq, true),
|
|
822
|
+
ne: buildMethodEntry('ne', SIG_NE, mNe, true),
|
|
823
|
+
keys: buildMethodEntry('keys', '||:list', mKeys, true),
|
|
824
|
+
values: buildMethodEntry('values', '||:list', mValues, true),
|
|
825
|
+
entries: buildMethodEntry('entries', '||:list', mEntries, true),
|
|
810
826
|
});
|
|
811
827
|
BUILTIN_METHODS.number = Object.freeze({
|
|
812
828
|
empty: buildMethodEntry('empty', SIG_EMPTY, mEmpty),
|
|
813
|
-
eq: buildMethodEntry('eq', SIG_EQ, mEq),
|
|
814
|
-
ne: buildMethodEntry('ne', SIG_NE, mNe),
|
|
829
|
+
eq: buildMethodEntry('eq', SIG_EQ, mEq, true),
|
|
830
|
+
ne: buildMethodEntry('ne', SIG_NE, mNe, true),
|
|
815
831
|
lt: buildMethodEntry('lt', SIG_CMP, mLt),
|
|
816
832
|
gt: buildMethodEntry('gt', SIG_CMP, mGt),
|
|
817
833
|
le: buildMethodEntry('le', SIG_CMP, mLe),
|
|
@@ -819,18 +835,21 @@ BUILTIN_METHODS.number = Object.freeze({
|
|
|
819
835
|
});
|
|
820
836
|
BUILTIN_METHODS.bool = Object.freeze({
|
|
821
837
|
empty: buildMethodEntry('empty', SIG_EMPTY, mEmpty),
|
|
822
|
-
eq: buildMethodEntry('eq', SIG_EQ, mEq),
|
|
823
|
-
ne: buildMethodEntry('ne', SIG_NE, mNe),
|
|
838
|
+
eq: buildMethodEntry('eq', SIG_EQ, mEq, true),
|
|
839
|
+
ne: buildMethodEntry('ne', SIG_NE, mNe, true),
|
|
824
840
|
});
|
|
825
841
|
// [ASSUMPTION] vector is a 6th group beyond the 5 specified basic types.
|
|
826
842
|
// The 7 vector methods do not belong to string/list/dict/number/bool.
|
|
827
843
|
// Adding this group ensures all 42 methods are accessible (AC-36).
|
|
828
844
|
BUILTIN_METHODS.vector = Object.freeze({
|
|
829
|
-
dimensions: buildMethodEntry('dimensions', '||:number', mDimensions),
|
|
830
|
-
model: buildMethodEntry('model', '||:string', mModel),
|
|
831
|
-
similarity: buildMethodEntry('similarity', '|other: any|:number', mSimilarity),
|
|
832
|
-
dot: buildMethodEntry('dot', '|other: any|:number', mDot),
|
|
833
|
-
distance: buildMethodEntry('distance', '|other: any|:number', mDistance),
|
|
834
|
-
norm: buildMethodEntry('norm', '||:number', mNorm),
|
|
835
|
-
normalize: buildMethodEntry('normalize', '||:any', mNormalize),
|
|
845
|
+
dimensions: buildMethodEntry('dimensions', '||:number', mDimensions, true),
|
|
846
|
+
model: buildMethodEntry('model', '||:string', mModel, true),
|
|
847
|
+
similarity: buildMethodEntry('similarity', '|other: any|:number', mSimilarity, true),
|
|
848
|
+
dot: buildMethodEntry('dot', '|other: any|:number', mDot, true),
|
|
849
|
+
distance: buildMethodEntry('distance', '|other: any|:number', mDistance, true),
|
|
850
|
+
norm: buildMethodEntry('norm', '||:number', mNorm, true),
|
|
851
|
+
normalize: buildMethodEntry('normalize', '||:any', mNormalize, true),
|
|
836
852
|
});
|
|
853
|
+
// Populate registration methods from BUILTIN_METHODS at module load time.
|
|
854
|
+
// No circular dependency: type-registrations.ts does not import builtins.ts.
|
|
855
|
+
populateBuiltinMethods(BUILTIN_METHODS);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ApplicationCallable } from '../core/callable.js';
|
|
2
2
|
import type { ExtensionEvent, RuntimeCallbacks } from '../core/types.js';
|
|
3
|
+
import type { RillValue } from '../core/values.js';
|
|
3
4
|
/**
|
|
4
5
|
* Minimal interface for extension event emission.
|
|
5
6
|
* Allows emitExtensionEvent to accept any context with callbacks.
|
|
@@ -9,27 +10,20 @@ interface RuntimeContextLike {
|
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* Result object returned by extension factories.
|
|
12
|
-
* Contains
|
|
13
|
+
* Contains the mounted RillValue with optional lifecycle hooks.
|
|
14
|
+
* Lifecycle hooks live on the factory result, not on the value dict (DD-1).
|
|
13
15
|
*/
|
|
14
|
-
export interface
|
|
15
|
-
|
|
16
|
+
export interface ExtensionFactoryResult {
|
|
17
|
+
readonly value: RillValue;
|
|
16
18
|
dispose?: () => void | Promise<void>;
|
|
17
19
|
suspend?: () => unknown;
|
|
18
20
|
restore?: (state: unknown) => void;
|
|
19
21
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Result object returned by hoistExtension.
|
|
22
|
-
* Separates functions from dispose for safe createRuntimeContext usage.
|
|
23
|
-
*/
|
|
24
|
-
export interface HoistedExtension {
|
|
25
|
-
functions: Record<string, RillFunction>;
|
|
26
|
-
dispose?: () => void | Promise<void>;
|
|
27
|
-
}
|
|
28
22
|
/**
|
|
29
23
|
* Factory function contract for creating extensions.
|
|
30
24
|
* Accepts typed configuration and returns isolated instance.
|
|
31
25
|
*/
|
|
32
|
-
export type ExtensionFactory<TConfig> = (config: TConfig) =>
|
|
26
|
+
export type ExtensionFactory<TConfig> = (config: TConfig) => ExtensionFactoryResult | Promise<ExtensionFactoryResult>;
|
|
33
27
|
/**
|
|
34
28
|
* Descriptor for a single configuration field in an extension schema.
|
|
35
29
|
* The secret flag is advisory: harness tooling uses it to mask or omit values.
|
|
@@ -72,18 +66,17 @@ export interface ExtensionManifest {
|
|
|
72
66
|
* - mounts(): List all configured mounts
|
|
73
67
|
*/
|
|
74
68
|
export type KvExtensionContract = {
|
|
75
|
-
readonly get:
|
|
76
|
-
readonly get_or:
|
|
77
|
-
readonly set:
|
|
78
|
-
readonly merge:
|
|
79
|
-
readonly delete:
|
|
80
|
-
readonly keys:
|
|
81
|
-
readonly has:
|
|
82
|
-
readonly clear:
|
|
83
|
-
readonly getAll:
|
|
84
|
-
readonly schema:
|
|
85
|
-
readonly mounts:
|
|
86
|
-
readonly dispose?: (() => void | Promise<void>) | undefined;
|
|
69
|
+
readonly get: ApplicationCallable;
|
|
70
|
+
readonly get_or: ApplicationCallable;
|
|
71
|
+
readonly set: ApplicationCallable;
|
|
72
|
+
readonly merge: ApplicationCallable;
|
|
73
|
+
readonly delete: ApplicationCallable;
|
|
74
|
+
readonly keys: ApplicationCallable;
|
|
75
|
+
readonly has: ApplicationCallable;
|
|
76
|
+
readonly clear: ApplicationCallable;
|
|
77
|
+
readonly getAll: ApplicationCallable;
|
|
78
|
+
readonly schema: ApplicationCallable;
|
|
79
|
+
readonly mounts: ApplicationCallable;
|
|
87
80
|
};
|
|
88
81
|
/**
|
|
89
82
|
* Contract type for fs extension implementations.
|
|
@@ -104,106 +97,19 @@ export type KvExtensionContract = {
|
|
|
104
97
|
* - mounts(): List all configured mounts
|
|
105
98
|
*/
|
|
106
99
|
export type FsExtensionContract = {
|
|
107
|
-
readonly read:
|
|
108
|
-
readonly write:
|
|
109
|
-
readonly append:
|
|
110
|
-
readonly list:
|
|
111
|
-
readonly find:
|
|
112
|
-
readonly exists:
|
|
113
|
-
readonly remove:
|
|
114
|
-
readonly stat:
|
|
115
|
-
readonly mkdir:
|
|
116
|
-
readonly copy:
|
|
117
|
-
readonly move:
|
|
118
|
-
readonly mounts:
|
|
119
|
-
readonly dispose?: (() => void | Promise<void>) | undefined;
|
|
120
|
-
};
|
|
121
|
-
/**
|
|
122
|
-
* Contract type for llm extension implementations.
|
|
123
|
-
* Enforces exact function structure for compile-time verification.
|
|
124
|
-
*
|
|
125
|
-
* Backend implementations must provide all 6 functions:
|
|
126
|
-
* - message(text, options): Send single message
|
|
127
|
-
* - messages(messages, options): Multi-turn conversation
|
|
128
|
-
* - embed(text): Generate embedding vector
|
|
129
|
-
* - embed_batch(texts): Batch embeddings
|
|
130
|
-
* - tool_loop(prompt, options): Tool use orchestration
|
|
131
|
-
* - generate(prompt, options): Structured output extraction
|
|
132
|
-
*/
|
|
133
|
-
export type LlmExtensionContract = {
|
|
134
|
-
readonly message: RillFunction;
|
|
135
|
-
readonly messages: RillFunction;
|
|
136
|
-
readonly embed: RillFunction;
|
|
137
|
-
readonly embed_batch: RillFunction;
|
|
138
|
-
readonly tool_loop: RillFunction;
|
|
139
|
-
readonly generate: RillFunction;
|
|
140
|
-
readonly dispose?: (() => void | Promise<void>) | undefined;
|
|
141
|
-
};
|
|
142
|
-
/**
|
|
143
|
-
* Contract type for vector extension implementations.
|
|
144
|
-
* Enforces exact function structure for compile-time verification.
|
|
145
|
-
*
|
|
146
|
-
* Backend implementations must provide all 11 functions:
|
|
147
|
-
* - upsert(id, vector, metadata): Insert or update vector
|
|
148
|
-
* - upsert_batch(items): Batch insert/update
|
|
149
|
-
* - search(vector, options): Search k nearest neighbors
|
|
150
|
-
* - get(id): Fetch vector by ID
|
|
151
|
-
* - delete(id): Delete vector by ID
|
|
152
|
-
* - delete_batch(ids): Batch delete
|
|
153
|
-
* - count(): Count vectors in collection
|
|
154
|
-
* - create_collection(name, options): Create collection
|
|
155
|
-
* - delete_collection(name): Delete collection
|
|
156
|
-
* - list_collections(): List all collections
|
|
157
|
-
* - describe(): Get collection metadata
|
|
158
|
-
*/
|
|
159
|
-
export type VectorExtensionContract = {
|
|
160
|
-
readonly upsert: RillFunction;
|
|
161
|
-
readonly upsert_batch: RillFunction;
|
|
162
|
-
readonly search: RillFunction;
|
|
163
|
-
readonly get: RillFunction;
|
|
164
|
-
readonly delete: RillFunction;
|
|
165
|
-
readonly delete_batch: RillFunction;
|
|
166
|
-
readonly count: RillFunction;
|
|
167
|
-
readonly create_collection: RillFunction;
|
|
168
|
-
readonly delete_collection: RillFunction;
|
|
169
|
-
readonly list_collections: RillFunction;
|
|
170
|
-
readonly describe: RillFunction;
|
|
171
|
-
readonly dispose?: (() => void | Promise<void>) | undefined;
|
|
100
|
+
readonly read: ApplicationCallable;
|
|
101
|
+
readonly write: ApplicationCallable;
|
|
102
|
+
readonly append: ApplicationCallable;
|
|
103
|
+
readonly list: ApplicationCallable;
|
|
104
|
+
readonly find: ApplicationCallable;
|
|
105
|
+
readonly exists: ApplicationCallable;
|
|
106
|
+
readonly remove: ApplicationCallable;
|
|
107
|
+
readonly stat: ApplicationCallable;
|
|
108
|
+
readonly mkdir: ApplicationCallable;
|
|
109
|
+
readonly copy: ApplicationCallable;
|
|
110
|
+
readonly move: ApplicationCallable;
|
|
111
|
+
readonly mounts: ApplicationCallable;
|
|
172
112
|
};
|
|
173
|
-
/**
|
|
174
|
-
* Prefix all function names in an extension with a namespace.
|
|
175
|
-
*
|
|
176
|
-
* @param namespace - Alphanumeric string with underscores/hyphens (e.g., "fs", "claude_code")
|
|
177
|
-
* @param functions - Extension result with function definitions
|
|
178
|
-
* @returns New ExtensionResult with prefixed function names (namespace::functionName)
|
|
179
|
-
* @throws {RuntimeError} RUNTIME_TYPE_ERROR if namespace is invalid
|
|
180
|
-
*
|
|
181
|
-
* @example
|
|
182
|
-
* ```typescript
|
|
183
|
-
* const fs = createFsExtension();
|
|
184
|
-
* const prefixed = prefixFunctions("fs", fs);
|
|
185
|
-
* // { "fs::read": ..., "fs::write": ..., dispose: ... }
|
|
186
|
-
* ```
|
|
187
|
-
*/
|
|
188
|
-
export declare function prefixFunctions(namespace: string, functions: ExtensionResult): ExtensionResult;
|
|
189
|
-
/**
|
|
190
|
-
* Separate dispose from functions for safe createRuntimeContext usage.
|
|
191
|
-
* Wraps prefixFunctions and returns separated structure.
|
|
192
|
-
*
|
|
193
|
-
* @param namespace - String matching /^[a-zA-Z0-9_-]+$/
|
|
194
|
-
* @param extension - Output from extension factory
|
|
195
|
-
* @returns Separated functions and dispose handler
|
|
196
|
-
* @throws {Error} If namespace is empty
|
|
197
|
-
* @throws {Error} If namespace has invalid format
|
|
198
|
-
* @throws {TypeError} If extension is null or undefined
|
|
199
|
-
*
|
|
200
|
-
* @example
|
|
201
|
-
* ```typescript
|
|
202
|
-
* const { functions, dispose } = hoistExtension('db', dbExtension);
|
|
203
|
-
* const ctx = createRuntimeContext({ functions });
|
|
204
|
-
* ```
|
|
205
|
-
*/
|
|
206
|
-
export declare function hoistExtension(namespace: string, extension: ExtensionResult): HoistedExtension;
|
|
207
113
|
/**
|
|
208
114
|
* Emit an extension event with auto-generated timestamp.
|
|
209
115
|
* Adds ISO timestamp if event.timestamp is undefined, then calls onLogEvent callback.
|
|
@@ -1,96 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prefix all function names in an extension with a namespace.
|
|
3
|
-
*
|
|
4
|
-
* @param namespace - Alphanumeric string with underscores/hyphens (e.g., "fs", "claude_code")
|
|
5
|
-
* @param functions - Extension result with function definitions
|
|
6
|
-
* @returns New ExtensionResult with prefixed function names (namespace::functionName)
|
|
7
|
-
* @throws {RuntimeError} RUNTIME_TYPE_ERROR if namespace is invalid
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* const fs = createFsExtension();
|
|
12
|
-
* const prefixed = prefixFunctions("fs", fs);
|
|
13
|
-
* // { "fs::read": ..., "fs::write": ..., dispose: ... }
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
export function prefixFunctions(namespace, functions) {
|
|
17
|
-
// EC-7: Extension not object
|
|
18
|
-
if (typeof functions !== 'object' ||
|
|
19
|
-
functions === null ||
|
|
20
|
-
Array.isArray(functions)) {
|
|
21
|
-
throw new TypeError('Extension must be an object');
|
|
22
|
-
}
|
|
23
|
-
// EC-6: Invalid namespace format
|
|
24
|
-
const NAMESPACE_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
25
|
-
if (!NAMESPACE_PATTERN.test(namespace)) {
|
|
26
|
-
throw new Error('Invalid namespace format: must match /^[a-zA-Z0-9_-]+$/');
|
|
27
|
-
}
|
|
28
|
-
// Create new object with prefixed keys
|
|
29
|
-
const result = {};
|
|
30
|
-
for (const [name, definition] of Object.entries(functions)) {
|
|
31
|
-
// Skip lifecycle hooks during prefixing
|
|
32
|
-
if (name === 'dispose' || name === 'suspend' || name === 'restore')
|
|
33
|
-
continue;
|
|
34
|
-
result[`${namespace}::${name}`] = definition;
|
|
35
|
-
}
|
|
36
|
-
// Preserve lifecycle hooks if present
|
|
37
|
-
const resultWithHooks = result;
|
|
38
|
-
if (functions.dispose !== undefined) {
|
|
39
|
-
resultWithHooks.dispose = functions.dispose;
|
|
40
|
-
}
|
|
41
|
-
if (functions.suspend !== undefined) {
|
|
42
|
-
resultWithHooks.suspend = functions.suspend;
|
|
43
|
-
}
|
|
44
|
-
if (functions.restore !== undefined) {
|
|
45
|
-
resultWithHooks.restore = functions.restore;
|
|
46
|
-
}
|
|
47
|
-
return resultWithHooks;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Separate dispose from functions for safe createRuntimeContext usage.
|
|
51
|
-
* Wraps prefixFunctions and returns separated structure.
|
|
52
|
-
*
|
|
53
|
-
* @param namespace - String matching /^[a-zA-Z0-9_-]+$/
|
|
54
|
-
* @param extension - Output from extension factory
|
|
55
|
-
* @returns Separated functions and dispose handler
|
|
56
|
-
* @throws {Error} If namespace is empty
|
|
57
|
-
* @throws {Error} If namespace has invalid format
|
|
58
|
-
* @throws {TypeError} If extension is null or undefined
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```typescript
|
|
62
|
-
* const { functions, dispose } = hoistExtension('db', dbExtension);
|
|
63
|
-
* const ctx = createRuntimeContext({ functions });
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export function hoistExtension(namespace, extension) {
|
|
67
|
-
// EC-3: Null/undefined extension
|
|
68
|
-
if (extension === null || extension === undefined) {
|
|
69
|
-
throw new TypeError('Extension cannot be null or undefined');
|
|
70
|
-
}
|
|
71
|
-
// EC-2: Empty namespace
|
|
72
|
-
if (namespace === '') {
|
|
73
|
-
throw new Error('Namespace cannot be empty');
|
|
74
|
-
}
|
|
75
|
-
// EC-1: Invalid namespace format
|
|
76
|
-
const NAMESPACE_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
77
|
-
if (!NAMESPACE_PATTERN.test(namespace)) {
|
|
78
|
-
throw new Error('Invalid namespace format: must match /^[a-zA-Z0-9_-]+$/');
|
|
79
|
-
}
|
|
80
|
-
// Call prefixFunctions internally
|
|
81
|
-
const prefixed = prefixFunctions(namespace, extension);
|
|
82
|
-
// Extract dispose from result
|
|
83
|
-
const { dispose, ...functions } = prefixed;
|
|
84
|
-
// Return separated structure
|
|
85
|
-
const result = {
|
|
86
|
-
functions: functions,
|
|
87
|
-
};
|
|
88
|
-
// Only add dispose if it exists (exactOptionalPropertyTypes)
|
|
89
|
-
if (dispose !== undefined) {
|
|
90
|
-
result.dispose = dispose;
|
|
91
|
-
}
|
|
92
|
-
return result;
|
|
93
|
-
}
|
|
94
1
|
/**
|
|
95
2
|
* Emit an extension event with auto-generated timestamp.
|
|
96
3
|
* Adds ISO timestamp if event.timestamp is undefined, then calls onLogEvent callback.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Context Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates a pre-wired RuntimeContext from extension value maps.
|
|
5
|
+
* Designed for testing and lightweight embedding without rill-config.
|
|
6
|
+
*/
|
|
7
|
+
import type { RuntimeContext } from '../core/types.js';
|
|
8
|
+
import { type RillValue } from '../core/values.js';
|
|
9
|
+
/**
|
|
10
|
+
* Error thrown when extension binding generation fails.
|
|
11
|
+
* Mirrors the ExtensionBindingError in rill-config for core-only usage.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ExtensionBindingError extends Error {
|
|
14
|
+
readonly code: "EXTENSION_BINDING";
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a RuntimeContext pre-wired with extension values.
|
|
19
|
+
* Builds extension bindings, registers ext and module resolvers,
|
|
20
|
+
* and returns a context ready for execute().
|
|
21
|
+
*
|
|
22
|
+
* @throws {TypeError} when an extension value is undefined (EC-9)
|
|
23
|
+
* @throws {ExtensionBindingError} when binding generation fails (EC-10)
|
|
24
|
+
*/
|
|
25
|
+
export declare function createTestContext(extensions: Record<string, {
|
|
26
|
+
value: RillValue;
|
|
27
|
+
dispose?: () => void | Promise<void>;
|
|
28
|
+
}>): RuntimeContext;
|