@xsai/stream-object 0.0.28 → 0.0.30

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 (3) hide show
  1. package/dist/index.d.ts +38 -10
  2. package/dist/index.js +235 -230
  3. package/package.json +10 -11
package/dist/index.d.ts CHANGED
@@ -28,7 +28,7 @@ Matches any primitive, `void`, `Date`, or `RegExp` value.
28
28
  type BuiltIns = Primitive | void | Date | RegExp;
29
29
 
30
30
  /**
31
- @see PartialDeep
31
+ @see {@link PartialDeep}
32
32
  */
33
33
  type PartialDeepOptions = {
34
34
  /**
@@ -37,6 +37,32 @@ type PartialDeepOptions = {
37
37
  @default false
38
38
  */
39
39
  readonly recurseIntoArrays?: boolean;
40
+
41
+ /**
42
+ Allows `undefined` values in non-tuple arrays.
43
+
44
+ - When set to `true`, elements of non-tuple arrays can be `undefined`.
45
+ - When set to `false`, only explicitly defined elements are allowed in non-tuple arrays, ensuring stricter type checking.
46
+
47
+ @default true
48
+
49
+ @example
50
+ You can prevent `undefined` values in non-tuple arrays by passing `{recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}` as the second type argument:
51
+
52
+ ```
53
+ import type {PartialDeep} from 'type-fest';
54
+
55
+ type Settings = {
56
+ languages: string[];
57
+ };
58
+
59
+ declare const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}>;
60
+
61
+ partialSettings.languages = [undefined]; // Error
62
+ partialSettings.languages = []; // Ok
63
+ ```
64
+ */
65
+ readonly allowUndefinedInNonTupleArrays?: boolean;
40
66
  };
41
67
 
42
68
  /**
@@ -52,12 +78,12 @@ import type {PartialDeep} from 'type-fest';
52
78
 
53
79
  const settings: Settings = {
54
80
  textEditor: {
55
- fontSize: 14;
56
- fontColor: '#000000';
57
- fontWeight: 400;
58
- }
59
- autocomplete: false;
60
- autosave: true;
81
+ fontSize: 14,
82
+ fontColor: '#000000',
83
+ fontWeight: 400
84
+ },
85
+ autocomplete: false,
86
+ autosave: true
61
87
  };
62
88
 
63
89
  const applySavedSettings = (savedSettings: PartialDeep<Settings>) => {
@@ -72,7 +98,7 @@ By default, this does not affect elements in array and tuple types. You can chan
72
98
  ```
73
99
  import type {PartialDeep} from 'type-fest';
74
100
 
75
- interface Settings {
101
+ type Settings = {
76
102
  languages: string[];
77
103
  }
78
104
 
@@ -81,6 +107,8 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
81
107
  };
82
108
  ```
83
109
 
110
+ @see {@link PartialDeepOptions}
111
+
84
112
  @category Object
85
113
  @category Array
86
114
  @category Set
@@ -101,8 +129,8 @@ type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIn
101
129
  ? Options['recurseIntoArrays'] extends true
102
130
  ? ItemType[] extends T // Test for arrays (non-tuples) specifically
103
131
  ? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
104
- ? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
105
- : Array<PartialDeep<ItemType | undefined, Options>>
132
+ ? ReadonlyArray<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
133
+ : Array<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
106
134
  : PartialObjectDeep<T, Options> // Tuples behave properly
107
135
  : T // If they don't opt into array testing, just use the original type
108
136
  : PartialObjectDeep<T, Options>
package/dist/index.js CHANGED
@@ -1,247 +1,252 @@
1
1
  import { toJSONSchema } from '@typeschema/main';
2
- import { clean } from '@xsai/shared';
3
2
  import { streamText } from '@xsai/stream-text';
4
3
 
5
4
  var parse = {};
6
5
 
7
- (function (exports) {
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.parse = void 0;
10
- function parse(s) {
11
- if (s === undefined) {
12
- return undefined;
13
- }
14
- if (s === null) {
15
- return null;
16
- }
17
- if (s === '') {
18
- return '';
19
- }
20
- // remove incomplete escaped characters at the end of the string
21
- s = s.replace(/\\+$/, match => match.length % 2 === 0 ? match : match.slice(0, -1));
22
- try {
23
- return JSON.parse(s);
24
- }
25
- catch (e) {
26
- const [data, reminding] = s.trimLeft()[0] === ':'
27
- ? parseAny(s, e)
28
- : parseAny(s, e, parseStringWithoutQuote);
29
- parse.lastParseReminding = reminding;
30
- if (parse.onExtraToken && reminding.length > 0) {
31
- parse.onExtraToken(s, data, reminding);
32
- }
33
- return data;
34
- }
35
- }
36
- exports.parse = parse;
37
- (function (parse) {
38
- parse.onExtraToken = (text, data, reminding) => {
39
- console.error('parsed json with extra tokens:', {
40
- text,
41
- data,
42
- reminding,
43
- });
44
- };
45
- })(parse = exports.parse || (exports.parse = {}));
46
- function parseAny(s, e, fallback) {
47
- const parser = parsers[s[0]] || fallback;
48
- if (!parser) {
49
- console.error(`no parser registered for ${JSON.stringify(s[0])}:`, { s });
50
- throw e;
51
- }
52
- return parser(s, e);
53
- }
54
- function parseStringCasual(s, e, delimiters) {
55
- if (s[0] === '"') {
56
- return parseString(s);
57
- }
58
- if (s[0] === "'") {
59
- return parseSingleQuoteString(s);
60
- }
61
- return parseStringWithoutQuote(s, e, delimiters);
62
- }
63
- const parsers = {};
64
- function skipSpace(s) {
65
- return s.trimLeft();
66
- }
67
- parsers[' '] = parseSpace;
68
- parsers['\r'] = parseSpace;
69
- parsers['\n'] = parseSpace;
70
- parsers['\t'] = parseSpace;
71
- function parseSpace(s, e) {
72
- s = skipSpace(s);
73
- return parseAny(s, e);
74
- }
75
- parsers['['] = parseArray;
76
- function parseArray(s, e) {
77
- s = s.substr(1); // skip starting '['
78
- const acc = [];
79
- s = skipSpace(s);
80
- for (; s.length > 0;) {
81
- if (s[0] === ']') {
82
- s = s.substr(1); // skip ending ']'
83
- break;
84
- }
85
- const res = parseAny(s, e, (s, e) => parseStringWithoutQuote(s, e, [',', ']']));
86
- acc.push(res[0]);
87
- s = res[1];
88
- s = skipSpace(s);
89
- if (s[0] === ',') {
90
- s = s.substring(1);
91
- s = skipSpace(s);
92
- }
93
- }
94
- return [acc, s];
95
- }
96
- for (const c of '0123456789.-'.slice()) {
97
- parsers[c] = parseNumber;
98
- }
99
- function parseNumber(s) {
100
- for (let i = 0; i < s.length; i++) {
101
- const c = s[i];
102
- if (parsers[c] === parseNumber) {
103
- continue;
104
- }
105
- const num = s.substring(0, i);
106
- s = s.substring(i);
107
- return [numToStr(num), s];
108
- }
109
- return [numToStr(s), ''];
110
- }
111
- function numToStr(s) {
112
- if (s === '-') {
113
- return -0;
114
- }
115
- const num = +s;
116
- if (Number.isNaN(num)) {
117
- return s;
118
- }
119
- return num;
120
- }
121
- parsers['"'] = parseString;
122
- function parseString(s) {
123
- for (let i = 1; i < s.length; i++) {
124
- const c = s[i];
125
- if (c === '\\') {
126
- i++;
127
- continue;
128
- }
129
- if (c === '"') {
130
- const str = fixEscapedCharacters(s.substring(0, i + 1));
131
- s = s.substring(i + 1);
132
- return [JSON.parse(str), s];
133
- }
134
- }
135
- return [JSON.parse(fixEscapedCharacters(s) + '"'), ''];
136
- }
137
- function fixEscapedCharacters(s) {
138
- return s.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r');
139
- }
140
- parsers["'"] = parseSingleQuoteString;
141
- function parseSingleQuoteString(s) {
142
- for (let i = 1; i < s.length; i++) {
143
- const c = s[i];
144
- if (c === '\\') {
145
- i++;
146
- continue;
147
- }
148
- if (c === "'") {
149
- const str = fixEscapedCharacters(s.substring(0, i + 1));
150
- s = s.substring(i + 1);
151
- return [JSON.parse('"' + str.slice(1, -1) + '"'), s];
152
- }
153
- }
154
- return [JSON.parse('"' + fixEscapedCharacters(s.slice(1)) + '"'), ''];
155
- }
156
- function parseStringWithoutQuote(s, e, delimiters = [' ']) {
157
- const index = Math.min(...delimiters.map(delimiter => {
158
- const index = s.indexOf(delimiter);
159
- return index === -1 ? s.length : index;
160
- }));
161
- const value = s.substring(0, index).trim();
162
- const rest = s.substring(index);
163
- return [value, rest];
164
- }
165
- parsers['{'] = parseObject;
166
- function parseObject(s, e) {
167
- s = s.substr(1); // skip starting '{'
168
- const acc = {};
169
- s = skipSpace(s);
170
- for (; s.length > 0;) {
171
- if (s[0] === '}') {
172
- s = s.substr(1); // skip ending '}'
173
- break;
174
- }
175
- const keyRes = parseStringCasual(s, e, [':', '}']);
176
- const key = keyRes[0];
177
- s = keyRes[1];
178
- s = skipSpace(s);
179
- if (s[0] !== ':') {
180
- acc[key] = undefined;
181
- break;
182
- }
183
- s = s.substr(1); // skip ':'
184
- s = skipSpace(s);
185
- if (s.length === 0) {
186
- acc[key] = undefined;
187
- break;
188
- }
189
- const valueRes = parseAny(s, e);
190
- acc[key] = valueRes[0];
191
- s = valueRes[1];
192
- s = skipSpace(s);
193
- if (s[0] === ',') {
194
- s = s.substr(1);
195
- s = skipSpace(s);
196
- }
197
- }
198
- return [acc, s];
199
- }
200
- parsers['t'] = parseTrue;
201
- function parseTrue(s, e) {
202
- return parseToken(s, `true`, true, e);
203
- }
204
- parsers['f'] = parseFalse;
205
- function parseFalse(s, e) {
206
- return parseToken(s, `false`, false, e);
207
- }
208
- parsers['n'] = parseNull;
209
- function parseNull(s, e) {
210
- return parseToken(s, `null`, null, e);
211
- }
212
- function parseToken(s, tokenStr, tokenVal, e) {
213
- for (let i = tokenStr.length; i >= 1; i--) {
214
- if (s.startsWith(tokenStr.slice(0, i))) {
215
- return [tokenVal, s.slice(i)];
216
- }
217
- }
218
- /* istanbul ignore next */
219
- {
220
- const prefix = JSON.stringify(s.slice(0, tokenStr.length));
221
- console.error(`unknown token starting with ${prefix}:`, { s });
222
- throw e;
223
- }
224
- }
225
-
226
- } (parse));
6
+ var hasRequiredParse;
227
7
 
228
- const streamObject = async (options) => await streamText({
8
+ function requireParse () {
9
+ if (hasRequiredParse) return parse;
10
+ hasRequiredParse = 1;
11
+ (function (exports) {
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.parse = undefined;
14
+ function parse(s) {
15
+ if (s === undefined) {
16
+ return undefined;
17
+ }
18
+ if (s === null) {
19
+ return null;
20
+ }
21
+ if (s === '') {
22
+ return '';
23
+ }
24
+ // remove incomplete escaped characters at the end of the string
25
+ s = s.replace(/\\+$/, match => match.length % 2 === 0 ? match : match.slice(0, -1));
26
+ try {
27
+ return JSON.parse(s);
28
+ }
29
+ catch (e) {
30
+ const [data, reminding] = s.trimLeft()[0] === ':'
31
+ ? parseAny(s, e)
32
+ : parseAny(s, e, parseStringWithoutQuote);
33
+ parse.lastParseReminding = reminding;
34
+ if (parse.onExtraToken && reminding.length > 0) {
35
+ parse.onExtraToken(s, data, reminding);
36
+ }
37
+ return data;
38
+ }
39
+ }
40
+ exports.parse = parse;
41
+ (function (parse) {
42
+ parse.onExtraToken = (text, data, reminding) => {
43
+ console.error('parsed json with extra tokens:', {
44
+ text,
45
+ data,
46
+ reminding,
47
+ });
48
+ };
49
+ })(parse = exports.parse || (exports.parse = {}));
50
+ function parseAny(s, e, fallback) {
51
+ const parser = parsers[s[0]] || fallback;
52
+ if (!parser) {
53
+ console.error(`no parser registered for ${JSON.stringify(s[0])}:`, { s });
54
+ throw e;
55
+ }
56
+ return parser(s, e);
57
+ }
58
+ function parseStringCasual(s, e, delimiters) {
59
+ if (s[0] === '"') {
60
+ return parseString(s);
61
+ }
62
+ if (s[0] === "'") {
63
+ return parseSingleQuoteString(s);
64
+ }
65
+ return parseStringWithoutQuote(s, e, delimiters);
66
+ }
67
+ const parsers = {};
68
+ function skipSpace(s) {
69
+ return s.trimLeft();
70
+ }
71
+ parsers[' '] = parseSpace;
72
+ parsers['\r'] = parseSpace;
73
+ parsers['\n'] = parseSpace;
74
+ parsers['\t'] = parseSpace;
75
+ function parseSpace(s, e) {
76
+ s = skipSpace(s);
77
+ return parseAny(s, e);
78
+ }
79
+ parsers['['] = parseArray;
80
+ function parseArray(s, e) {
81
+ s = s.substr(1); // skip starting '['
82
+ const acc = [];
83
+ s = skipSpace(s);
84
+ for (; s.length > 0;) {
85
+ if (s[0] === ']') {
86
+ s = s.substr(1); // skip ending ']'
87
+ break;
88
+ }
89
+ const res = parseAny(s, e, (s, e) => parseStringWithoutQuote(s, e, [',', ']']));
90
+ acc.push(res[0]);
91
+ s = res[1];
92
+ s = skipSpace(s);
93
+ if (s[0] === ',') {
94
+ s = s.substring(1);
95
+ s = skipSpace(s);
96
+ }
97
+ }
98
+ return [acc, s];
99
+ }
100
+ for (const c of '0123456789.-'.slice()) {
101
+ parsers[c] = parseNumber;
102
+ }
103
+ function parseNumber(s) {
104
+ for (let i = 0; i < s.length; i++) {
105
+ const c = s[i];
106
+ if (parsers[c] === parseNumber) {
107
+ continue;
108
+ }
109
+ const num = s.substring(0, i);
110
+ s = s.substring(i);
111
+ return [numToStr(num), s];
112
+ }
113
+ return [numToStr(s), ''];
114
+ }
115
+ function numToStr(s) {
116
+ if (s === '-') {
117
+ return -0;
118
+ }
119
+ const num = +s;
120
+ if (Number.isNaN(num)) {
121
+ return s;
122
+ }
123
+ return num;
124
+ }
125
+ parsers['"'] = parseString;
126
+ function parseString(s) {
127
+ for (let i = 1; i < s.length; i++) {
128
+ const c = s[i];
129
+ if (c === '\\') {
130
+ i++;
131
+ continue;
132
+ }
133
+ if (c === '"') {
134
+ const str = fixEscapedCharacters(s.substring(0, i + 1));
135
+ s = s.substring(i + 1);
136
+ return [JSON.parse(str), s];
137
+ }
138
+ }
139
+ return [JSON.parse(fixEscapedCharacters(s) + '"'), ''];
140
+ }
141
+ function fixEscapedCharacters(s) {
142
+ return s.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r');
143
+ }
144
+ parsers["'"] = parseSingleQuoteString;
145
+ function parseSingleQuoteString(s) {
146
+ for (let i = 1; i < s.length; i++) {
147
+ const c = s[i];
148
+ if (c === '\\') {
149
+ i++;
150
+ continue;
151
+ }
152
+ if (c === "'") {
153
+ const str = fixEscapedCharacters(s.substring(0, i + 1));
154
+ s = s.substring(i + 1);
155
+ return [JSON.parse('"' + str.slice(1, -1) + '"'), s];
156
+ }
157
+ }
158
+ return [JSON.parse('"' + fixEscapedCharacters(s.slice(1)) + '"'), ''];
159
+ }
160
+ function parseStringWithoutQuote(s, e, delimiters = [' ']) {
161
+ const index = Math.min(...delimiters.map(delimiter => {
162
+ const index = s.indexOf(delimiter);
163
+ return index === -1 ? s.length : index;
164
+ }));
165
+ const value = s.substring(0, index).trim();
166
+ const rest = s.substring(index);
167
+ return [value, rest];
168
+ }
169
+ parsers['{'] = parseObject;
170
+ function parseObject(s, e) {
171
+ s = s.substr(1); // skip starting '{'
172
+ const acc = {};
173
+ s = skipSpace(s);
174
+ for (; s.length > 0;) {
175
+ if (s[0] === '}') {
176
+ s = s.substr(1); // skip ending '}'
177
+ break;
178
+ }
179
+ const keyRes = parseStringCasual(s, e, [':', '}']);
180
+ const key = keyRes[0];
181
+ s = keyRes[1];
182
+ s = skipSpace(s);
183
+ if (s[0] !== ':') {
184
+ acc[key] = undefined;
185
+ break;
186
+ }
187
+ s = s.substr(1); // skip ':'
188
+ s = skipSpace(s);
189
+ if (s.length === 0) {
190
+ acc[key] = undefined;
191
+ break;
192
+ }
193
+ const valueRes = parseAny(s, e);
194
+ acc[key] = valueRes[0];
195
+ s = valueRes[1];
196
+ s = skipSpace(s);
197
+ if (s[0] === ',') {
198
+ s = s.substr(1);
199
+ s = skipSpace(s);
200
+ }
201
+ }
202
+ return [acc, s];
203
+ }
204
+ parsers['t'] = parseTrue;
205
+ function parseTrue(s, e) {
206
+ return parseToken(s, `true`, true, e);
207
+ }
208
+ parsers['f'] = parseFalse;
209
+ function parseFalse(s, e) {
210
+ return parseToken(s, `false`, false, e);
211
+ }
212
+ parsers['n'] = parseNull;
213
+ function parseNull(s, e) {
214
+ return parseToken(s, `null`, null, e);
215
+ }
216
+ function parseToken(s, tokenStr, tokenVal, e) {
217
+ for (let i = tokenStr.length; i >= 1; i--) {
218
+ if (s.startsWith(tokenStr.slice(0, i))) {
219
+ return [tokenVal, s.slice(i)];
220
+ }
221
+ }
222
+ /* istanbul ignore next */
223
+ {
224
+ const prefix = JSON.stringify(s.slice(0, tokenStr.length));
225
+ console.error(`unknown token starting with ${prefix}:`, { s });
226
+ throw e;
227
+ }
228
+ }
229
+
230
+ } (parse));
231
+ return parse;
232
+ }
233
+
234
+ var parseExports = requireParse();
235
+
236
+ const streamObject = async (options) => streamText({
229
237
  ...options,
230
238
  response_format: {
231
239
  json_schema: {
232
240
  description: options.schemaDescription,
233
241
  name: options.schemaName ?? "json_schema",
234
- schema: await toJSONSchema(options.schema).then((json) => clean({
235
- ...json,
236
- $schema: void 0
237
- })),
242
+ schema: await toJSONSchema(options.schema),
238
243
  strict: true
239
244
  },
240
245
  type: "json_schema"
241
246
  },
242
- schema: void 0,
243
- schemaDescription: void 0,
244
- schemaName: void 0
247
+ schema: undefined,
248
+ schemaDescription: undefined,
249
+ schemaName: undefined
245
250
  }).then(({ chunkStream, finishReason, textStream: rawTextStream, usage }) => {
246
251
  const [textStream, rawPartialObjectStream] = rawTextStream.tee();
247
252
  let partialObjectData = "";
@@ -250,7 +255,7 @@ const streamObject = async (options) => await streamText({
250
255
  transform: (chunk, controller) => {
251
256
  partialObjectData += chunk;
252
257
  try {
253
- const data = parse.parse(partialObjectData);
258
+ const data = parseExports.parse(partialObjectData);
254
259
  if (JSON.stringify(partialObjectSnapshot) !== JSON.stringify(data)) {
255
260
  partialObjectSnapshot = data;
256
261
  controller.enqueue(data);
package/package.json CHANGED
@@ -1,44 +1,43 @@
1
1
  {
2
2
  "name": "@xsai/stream-object",
3
- "version": "0.0.28",
4
3
  "type": "module",
4
+ "version": "0.0.30",
5
+ "description": "extra-small AI SDK for Browser, Node.js, Deno, Bun or Edge Runtime.",
5
6
  "author": "Moeru AI",
6
7
  "license": "MIT",
7
8
  "homepage": "https://xsai.js.org",
8
- "description": "extra-small AI SDK for Browser, Node.js, Deno, Bun or Edge Runtime.",
9
- "keywords": [
10
- "xsai",
11
- "openai",
12
- "ai"
13
- ],
14
9
  "repository": {
15
10
  "type": "git",
16
11
  "url": "git+https://github.com/moeru-ai/xsai.git",
17
12
  "directory": "packages/stream-object"
18
13
  },
19
14
  "bugs": "https://github.com/moeru-ai/xsai/issues",
15
+ "keywords": [
16
+ "xsai",
17
+ "openai",
18
+ "ai"
19
+ ],
20
20
  "sideEffects": false,
21
- "main": "./dist/index.js",
22
- "types": "./dist/index.d.ts",
23
21
  "exports": {
24
22
  ".": {
25
23
  "types": "./dist/index.d.ts",
26
24
  "default": "./dist/index.js"
27
25
  }
28
26
  },
27
+ "main": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
29
  "files": [
30
30
  "dist"
31
31
  ],
32
32
  "dependencies": {
33
33
  "@typeschema/main": "^0.14.1",
34
- "@xsai/shared": "",
35
34
  "@xsai/stream-text": ""
36
35
  },
37
36
  "devDependencies": {
38
37
  "@gcornut/valibot-json-schema": "^0.42.0",
39
38
  "@xsai/providers": "",
40
39
  "best-effort-json-parser": "^1.1.2",
41
- "type-fest": "^4.31.0",
40
+ "type-fest": "^4.33.0",
42
41
  "valibot": "^0.42.1"
43
42
  },
44
43
  "scripts": {