spiceflow 0.0.7 → 1.0.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.
Files changed (151) hide show
  1. package/README.md +1 -171
  2. package/dist/client/errors.d.ts +7 -0
  3. package/dist/client/errors.d.ts.map +1 -0
  4. package/dist/client/errors.js +18 -0
  5. package/dist/client/errors.js.map +1 -0
  6. package/dist/client/index.d.ts +14 -0
  7. package/dist/client/index.d.ts.map +1 -0
  8. package/dist/client/index.js +376 -0
  9. package/dist/client/index.js.map +1 -0
  10. package/dist/client/types.d.ts +87 -0
  11. package/dist/client/types.d.ts.map +1 -0
  12. package/dist/client/types.js +2 -0
  13. package/dist/client/types.js.map +1 -0
  14. package/dist/client/utils.d.ts +2 -0
  15. package/dist/client/utils.d.ts.map +1 -0
  16. package/dist/client/utils.js +9 -0
  17. package/dist/client/utils.js.map +1 -0
  18. package/dist/client/ws.d.ts +15 -0
  19. package/dist/client/ws.d.ts.map +1 -0
  20. package/dist/client/ws.js +51 -0
  21. package/dist/client/ws.js.map +1 -0
  22. package/dist/client.test.d.ts +2 -0
  23. package/dist/client.test.d.ts.map +1 -0
  24. package/dist/client.test.js +237 -0
  25. package/dist/client.test.js.map +1 -0
  26. package/dist/elysia-fork/context.d.ts +87 -0
  27. package/dist/elysia-fork/context.d.ts.map +1 -0
  28. package/dist/elysia-fork/context.js +2 -0
  29. package/dist/elysia-fork/context.js.map +1 -0
  30. package/dist/elysia-fork/error.d.ts +246 -0
  31. package/dist/elysia-fork/error.d.ts.map +1 -0
  32. package/dist/elysia-fork/error.js +195 -0
  33. package/dist/elysia-fork/error.js.map +1 -0
  34. package/dist/elysia-fork/types.d.ts +652 -0
  35. package/dist/elysia-fork/types.d.ts.map +1 -0
  36. package/dist/elysia-fork/types.js +3 -0
  37. package/dist/elysia-fork/types.js.map +1 -0
  38. package/dist/elysia-fork/utils.d.ts +134 -0
  39. package/dist/elysia-fork/utils.d.ts.map +1 -0
  40. package/dist/elysia-fork/utils.js +70 -0
  41. package/dist/elysia-fork/utils.js.map +1 -0
  42. package/dist/spiceflow.d.ts +253 -0
  43. package/dist/spiceflow.d.ts.map +1 -0
  44. package/dist/spiceflow.js +500 -0
  45. package/dist/spiceflow.js.map +1 -0
  46. package/dist/spiceflow.test.d.ts +2 -0
  47. package/dist/spiceflow.test.d.ts.map +1 -0
  48. package/dist/spiceflow.test.js +225 -0
  49. package/dist/spiceflow.test.js.map +1 -0
  50. package/dist/stream.test.d.ts +2 -0
  51. package/dist/stream.test.d.ts.map +1 -0
  52. package/dist/stream.test.js +286 -0
  53. package/dist/stream.test.js.map +1 -0
  54. package/dist/types.d.ts +1 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +2 -0
  57. package/dist/types.js.map +1 -0
  58. package/dist/utils.d.ts +4 -20
  59. package/dist/utils.d.ts.map +1 -1
  60. package/dist/utils.js +17 -46
  61. package/dist/utils.js.map +1 -1
  62. package/package.json +12 -36
  63. package/src/client/errors.ts +21 -0
  64. package/src/client/index.ts +539 -0
  65. package/src/client/types.ts +233 -0
  66. package/src/client/utils.ts +7 -0
  67. package/src/client/ws.ts +99 -0
  68. package/src/client.test.ts +235 -0
  69. package/src/elysia-fork/context.ts +196 -0
  70. package/src/elysia-fork/error.ts +293 -0
  71. package/src/elysia-fork/types.ts +1454 -0
  72. package/src/elysia-fork/utils.ts +85 -0
  73. package/src/spiceflow.test.ts +290 -0
  74. package/src/spiceflow.ts +1266 -0
  75. package/src/stream.test.ts +342 -0
  76. package/src/types.ts +0 -0
  77. package/src/utils.ts +21 -70
  78. package/context.d.ts +0 -2
  79. package/context.js +0 -1
  80. package/dist/babel.test.d.ts +0 -2
  81. package/dist/babel.test.d.ts.map +0 -1
  82. package/dist/babel.test.js +0 -27
  83. package/dist/babel.test.js.map +0 -1
  84. package/dist/babelDebugOutputs.d.ts +0 -9
  85. package/dist/babelDebugOutputs.d.ts.map +0 -1
  86. package/dist/babelDebugOutputs.js +0 -34
  87. package/dist/babelDebugOutputs.js.map +0 -1
  88. package/dist/babelTransformRpc.d.ts +0 -19
  89. package/dist/babelTransformRpc.d.ts.map +0 -1
  90. package/dist/babelTransformRpc.js +0 -285
  91. package/dist/babelTransformRpc.js.map +0 -1
  92. package/dist/browser.d.ts +0 -8
  93. package/dist/browser.d.ts.map +0 -1
  94. package/dist/browser.js +0 -126
  95. package/dist/browser.js.map +0 -1
  96. package/dist/build.d.ts +0 -13
  97. package/dist/build.d.ts.map +0 -1
  98. package/dist/build.js +0 -230
  99. package/dist/build.js.map +0 -1
  100. package/dist/cli.d.ts +0 -3
  101. package/dist/cli.d.ts.map +0 -1
  102. package/dist/cli.js +0 -111
  103. package/dist/cli.js.map +0 -1
  104. package/dist/context-internal.d.ts +0 -20
  105. package/dist/context-internal.d.ts.map +0 -1
  106. package/dist/context-internal.js +0 -16
  107. package/dist/context-internal.js.map +0 -1
  108. package/dist/context.d.ts +0 -2
  109. package/dist/context.d.ts.map +0 -1
  110. package/dist/context.js +0 -2
  111. package/dist/context.js.map +0 -1
  112. package/dist/expose.d.ts +0 -6
  113. package/dist/expose.d.ts.map +0 -1
  114. package/dist/expose.js +0 -32
  115. package/dist/expose.js.map +0 -1
  116. package/dist/headers.d.ts +0 -2
  117. package/dist/headers.d.ts.map +0 -1
  118. package/dist/headers.js +0 -18
  119. package/dist/headers.js.map +0 -1
  120. package/dist/index.d.ts +0 -8
  121. package/dist/index.d.ts.map +0 -1
  122. package/dist/index.js +0 -23
  123. package/dist/index.js.map +0 -1
  124. package/dist/jsonRpc.d.ts +0 -32
  125. package/dist/jsonRpc.d.ts.map +0 -1
  126. package/dist/jsonRpc.js +0 -3
  127. package/dist/jsonRpc.js.map +0 -1
  128. package/dist/server.d.ts +0 -32
  129. package/dist/server.d.ts.map +0 -1
  130. package/dist/server.js +0 -292
  131. package/dist/server.js.map +0 -1
  132. package/headers.d.ts +0 -2
  133. package/headers.js +0 -1
  134. package/sdk-template/package.json +0 -22
  135. package/sdk-template/src/index.ts +0 -2
  136. package/sdk-template/src/v1/example.ts +0 -5
  137. package/sdk-template/src/v1/generator.ts +0 -12
  138. package/sdk-template/tsconfig.json +0 -16
  139. package/src/babel.test.ts +0 -35
  140. package/src/babelDebugOutputs.ts +0 -56
  141. package/src/babelTransformRpc.ts +0 -394
  142. package/src/browser.ts +0 -141
  143. package/src/build.ts +0 -298
  144. package/src/cli.ts +0 -132
  145. package/src/context-internal.ts +0 -36
  146. package/src/context.ts +0 -5
  147. package/src/expose.ts +0 -34
  148. package/src/headers.ts +0 -19
  149. package/src/index.ts +0 -34
  150. package/src/jsonRpc.ts +0 -43
  151. package/src/server.ts +0 -384
@@ -1,394 +0,0 @@
1
- import * as babel from '@babel/core';
2
- import generate from '@babel/generator';
3
- import { parse, parseExpression } from '@babel/parser';
4
- import type * as types from '@babel/types';
5
- import fs from 'fs';
6
- import path from 'path';
7
- import { WrapMethodMeta } from './server.js';
8
- import { annotateAsPure, directive, logger, removeExtension } from './utils.js';
9
-
10
- type Babel = { types: typeof types };
11
-
12
- function isAllowedTsExportDeclaration(
13
- declaration: babel.NodePath<babel.types.Declaration | null | undefined>,
14
- ): boolean {
15
- return (
16
- declaration.isTSTypeAliasDeclaration() ||
17
- declaration.isTSInterfaceDeclaration()
18
- );
19
- }
20
-
21
- const allowedExports = new Set([
22
- 'revalidate', //
23
- 'preferredRegion',
24
- 'runtime',
25
- 'maxDuration',
26
- 'fetchCache',
27
- 'dynamic',
28
- 'dynamicParams',
29
- 'GET',
30
- 'HEAD',
31
- ]);
32
-
33
- function getConfigObjectExpression(
34
- variable: babel.NodePath<babel.types.VariableDeclarator>,
35
- ) {
36
- const identifier = variable.get('id');
37
- const init = variable.get('init');
38
- if (
39
- identifier.isIdentifier() &&
40
- identifier.node.name === 'config' &&
41
- init.isObjectExpression()
42
- ) {
43
- const isEdge = isEdgeInConfig(init);
44
- return {
45
- isEdge,
46
- };
47
- }
48
- if (identifier.isIdentifier() && identifier.node.name === 'runtime') {
49
- const isEdge = init.isStringLiteral({ value: 'edge' });
50
- return {
51
- isEdge,
52
- };
53
- }
54
- return null;
55
- }
56
-
57
- export function getConfigObject(program: babel.NodePath<babel.types.Program>) {
58
- for (const statement of program.get('body')) {
59
- if (statement.isExportNamedDeclaration()) {
60
- const declaration = statement.get('declaration');
61
- if (declaration.isVariableDeclaration()) {
62
- for (const variable of declaration.get('declarations')) {
63
- const configObject = getConfigObjectExpression(variable);
64
- if (configObject) {
65
- return configObject;
66
- }
67
- }
68
- }
69
- }
70
- }
71
- return;
72
- }
73
-
74
- function isServerAction(program: babel.NodePath<babel.types.Program>): boolean {
75
- const dir = program.node.directives?.find(
76
- (x) => x.value?.value === directive,
77
- );
78
- return !!dir;
79
- // https://regex101.com/r/Wm6UvV/1
80
- // return /^("|')poor man's use server("|')(;?)\n/m.test(code);
81
- }
82
-
83
- function hasWrapMethod(program: babel.NodePath<babel.types.Program>) {
84
- // check if there is a function export called wrapMethod
85
- for (const statement of program.get('body')) {
86
- // also check the export { wrapMethod }
87
- if (statement.isExportNamedDeclaration()) {
88
- for (const specifier of statement.get('specifiers')) {
89
- if (
90
- specifier.node.exported.type === 'Identifier' &&
91
- specifier.node.exported.name === 'wrapMethod'
92
- ) {
93
- return true;
94
- }
95
- }
96
- }
97
- if (statement.isExportNamedDeclaration()) {
98
- const declaration = statement.get('declaration');
99
- if (declaration.isFunctionDeclaration()) {
100
- const identifier = declaration.get('id');
101
- if (identifier.node?.name === 'wrapMethod') {
102
- return true;
103
- }
104
- } else if (declaration.isVariableDeclaration()) {
105
- for (const variable of declaration.get('declarations')) {
106
- const id = variable.get('id');
107
- if (id.isIdentifier() && id.node.name === 'wrapMethod') {
108
- return true;
109
- }
110
- }
111
- }
112
- }
113
- }
114
-
115
- // return (
116
- // /export\s+function\s+wrapMethod\s*\(/m.test(code) ||
117
- // /export\s+(let|const)\s+wrapMethod\s*/m.test(code) ||
118
- // // https://regex101.com/r/nRaEVs/1
119
- // /export\s+\{[^}]*wrapMethod/m.test(code)
120
- // );
121
- }
122
-
123
- export function isEdgeInConfig(
124
- configObject?: babel.NodePath<babel.types.ObjectExpression>,
125
- ): boolean {
126
- if (!configObject) {
127
- return false;
128
- }
129
- for (const property of configObject.get('properties')) {
130
- if (!property.isObjectProperty()) {
131
- continue;
132
- }
133
- const key = property.get('key');
134
- const value = property.get('value');
135
-
136
- if (
137
- property.isObjectProperty() &&
138
- key.isIdentifier({ name: 'runtime' }) &&
139
- value.isStringLiteral({ value: 'edge' })
140
- ) {
141
- return true;
142
- }
143
- }
144
- return false;
145
- }
146
-
147
- export interface PluginOptions {
148
- isServer: boolean;
149
- rootDir: string;
150
- onMethod?: (method: WrapMethodMeta) => void;
151
- url?: string;
152
- }
153
-
154
- export default function (
155
- { types: t }: Babel,
156
- { rootDir, onMethod, isServer, url: rpcUrl }: PluginOptions,
157
- ): babel.PluginObj {
158
- return {
159
- visitor: {
160
- Program(program, state) {
161
- const { filename } = this.file.opts;
162
-
163
- if (!filename) {
164
- return;
165
- }
166
-
167
- const { isEdge } = getConfigObject(program) || {
168
- isEdge: false,
169
- };
170
-
171
- const isAction = isServerAction(program);
172
-
173
- if (!isAction) {
174
- logger.log(`Skipping ${filename} because it's not an action`);
175
- return;
176
- }
177
-
178
- logger.log(
179
- `Processing ${filename} as a ${
180
- isServer ? 'server' : 'client'
181
- } action`,
182
- );
183
-
184
- const hasWrap = hasWrapMethod(program);
185
-
186
- const rel = path.relative(rootDir, filename);
187
-
188
- const rpcRelativePath = rel
189
- .replace(/\.[j|t]sx?$/, '')
190
- // remove /pages at the start
191
- .replace(/^src\//, '')
192
- .replace(/\/index$/, '');
193
- let rpcPath = rpcUrl
194
- ? new URL(rpcRelativePath, rpcUrl).toString()
195
- : '/' + rpcRelativePath;
196
-
197
- const rpcMethodNames: string[] = [];
198
-
199
- const createRpcMethodIdentifier =
200
- program.scope.generateUidIdentifier('createRpcMethod');
201
-
202
- const createRpcMethod = (
203
- rpcMethod:
204
- | babel.types.ArrowFunctionExpression
205
- | babel.types.FunctionExpression,
206
- meta: WrapMethodMeta,
207
- ) => {
208
- return t.callExpression(createRpcMethodIdentifier, [
209
- rpcMethod,
210
- parseExpression(JSON.stringify(meta)),
211
-
212
- parseExpression(
213
- hasWrap
214
- ? `typeof wrapMethod === 'function' ? wrapMethod : undefined`
215
- : 'null',
216
- ),
217
- ]);
218
- };
219
-
220
- const generators = new Map<string, boolean>();
221
- for (const statement of program.get('body')) {
222
- if (statement.isExportNamedDeclaration()) {
223
- // check if function is async generator
224
-
225
- const declaration = statement.get('declaration');
226
- if (isAllowedTsExportDeclaration(declaration)) {
227
- // ignore
228
- } else if (declaration.isFunctionDeclaration()) {
229
- const identifier = declaration.get('id');
230
- const methodName = identifier.node?.name;
231
- if (methodName === 'wrapMethod') {
232
- continue;
233
- }
234
-
235
- const isGenerator = !!declaration.node.generator;
236
- generators.set(methodName!, isGenerator);
237
- if (!declaration.node.async) {
238
- throw declaration.buildCodeFrameError(
239
- 'rpc exports must be async functions',
240
- );
241
- }
242
-
243
- if (methodName) {
244
- rpcMethodNames.push(methodName);
245
- if (isServer) {
246
- // replace with wrapped
247
- statement.replaceWith(
248
- t.exportNamedDeclaration(
249
- t.variableDeclaration('const', [
250
- t.variableDeclarator(
251
- t.identifier(methodName),
252
- createRpcMethod(t.toExpression(declaration.node), {
253
- name: methodName,
254
- pathname: rpcPath,
255
- isGenerator,
256
- }),
257
- ),
258
- ]),
259
- ),
260
- );
261
- }
262
- }
263
- } else if (
264
- declaration.isVariableDeclaration() &&
265
- declaration.node.kind === 'const'
266
- ) {
267
- for (const variable of declaration.get('declarations')) {
268
- const init = variable.get('init');
269
-
270
- if (getConfigObjectExpression(variable)) {
271
- continue;
272
- }
273
- const node = variable.get('id');
274
-
275
- if (node.isIdentifier() && allowedExports.has(node.node.name)) {
276
- continue;
277
- }
278
- if (getConfigObjectExpression(variable)) {
279
- // ignore, this is the only allowed non-function export
280
- continue;
281
- }
282
- if (
283
- init.isFunctionExpression() ||
284
- init.isArrowFunctionExpression()
285
- ) {
286
- const { id } = variable.node;
287
- if (t.isIdentifier(id)) {
288
- const methodName = id.name;
289
- if (methodName === 'wrapMethod') {
290
- continue;
291
- }
292
- }
293
- if (!init.node.async) {
294
- throw init.buildCodeFrameError(
295
- 'rpc exports must be async functions',
296
- );
297
- }
298
-
299
- if (t.isIdentifier(id)) {
300
- const methodName = id.name;
301
- if (methodName === 'wrapMethod') {
302
- continue;
303
- }
304
- const isGenerator = !!init.node.generator;
305
- generators.set(methodName!, isGenerator);
306
- rpcMethodNames.push(methodName);
307
- if (isServer) {
308
- init.replaceWith(
309
- createRpcMethod(init.node, {
310
- name: methodName,
311
- pathname: rpcPath,
312
- isGenerator,
313
- }),
314
- );
315
- }
316
- }
317
- } else {
318
- throw variable.buildCodeFrameError(
319
- 'rpc exports must be static functions',
320
- );
321
- }
322
- }
323
- } else {
324
- for (const specifier of statement.get('specifiers')) {
325
- if (
326
- specifier?.node?.exported.type === 'Identifier' &&
327
- specifier?.node?.exported.name === 'wrapMethod'
328
- ) {
329
- continue;
330
- }
331
- throw specifier.buildCodeFrameError(
332
- 'rpc exports must be static functions',
333
- );
334
- }
335
- }
336
- } else if (statement.isExportDefaultDeclaration()) {
337
- throw statement.buildCodeFrameError(
338
- 'default exports are not allowed in rpc routes',
339
- );
340
- }
341
- }
342
-
343
- if (!isServer) {
344
- // Clear the whole body
345
- out: for (const statement of program.get('body')) {
346
- // don't remove if it's an export with name is config or runtime
347
- if (statement.isExportNamedDeclaration()) {
348
- const declaration = statement.get('declaration');
349
- if (declaration.isVariableDeclaration()) {
350
- for (const variable of declaration.get('declarations')) {
351
- const configObject = getConfigObjectExpression(variable);
352
- if (configObject) {
353
- continue out;
354
- }
355
- }
356
- }
357
- }
358
- statement.remove();
359
- }
360
-
361
- const outFile = path.resolve(
362
- rootDir,
363
- '../browser',
364
- path.relative(rootDir, filename),
365
- );
366
- program.node.directives = [];
367
- program.pushContainer('body', [
368
- ...(parse(
369
- `import { createRpcFetcher } from 'spiceflow/dist/browser.js';\n` +
370
- `import * as methods from './${
371
- removeExtension(
372
- path.relative(path.dirname(outFile), filename),
373
- ) + '.js'
374
- }'`,
375
- { sourceType: 'module' },
376
- ).program.body as any),
377
- ...rpcMethodNames.map((name) => {
378
- const isGenerator = !!generators.get(name);
379
- onMethod?.({ name, pathname: rpcPath, isGenerator });
380
- return parse(
381
- `export const ${name}: typeof methods['${name}'] = createRpcFetcher({ url: ${JSON.stringify(
382
- rpcPath,
383
- )}, method: ${JSON.stringify(
384
- name,
385
- )}, isGenerator: ${isGenerator} });`,
386
- { sourceType: 'module', plugins: ['typescript'] },
387
- ).program.body[0];
388
- }),
389
- ]);
390
- }
391
- },
392
- },
393
- };
394
- }
package/src/browser.ts DELETED
@@ -1,141 +0,0 @@
1
- import { EventSourceParserStream } from 'eventsource-parser/stream';
2
- import { JsonRpcRequest, JsonRpcResponse } from './jsonRpc.js';
3
-
4
- import superjson from 'superjson';
5
-
6
- type NextRpcCall = (...params: any[]) => any | AsyncGenerator<any>;
7
-
8
- let nextId = 1;
9
-
10
- export function createRpcFetcher({
11
- url,
12
- method,
13
- isGenerator,
14
- }: {
15
- url: string;
16
- method: string;
17
- isGenerator?: boolean;
18
- }): NextRpcCall {
19
- const controller = new AbortController();
20
- if (isGenerator) {
21
- const generator = async function* rpcFetchGenerator(...args) {
22
- const { json, meta } = superjson.serialize(args);
23
- const res = await fetch(url, {
24
- method: 'POST',
25
- headers: {
26
- Accept: 'text/event-stream',
27
- 'Content-Type': 'application/json',
28
- },
29
- signal: controller.signal,
30
- body: JSON.stringify({
31
- jsonrpc: '2.0',
32
- id: nextId++,
33
- method,
34
- params: json as any[],
35
- meta,
36
- } satisfies JsonRpcRequest),
37
- });
38
- if (res.status >= 400) {
39
- const json = await res.json();
40
- await handleJsonrpcError({ status: res.status, json });
41
- }
42
-
43
- if (!res.body) {
44
- throw new Error('No response body for generator action');
45
- }
46
- const eventStream = res.body
47
- .pipeThrough(new TextDecoderStream())
48
- .pipeThrough(new EventSourceParserStream())
49
- .getReader();
50
- let isClosed = false;
51
- try {
52
- while (true) {
53
- const { value: event, done } = await eventStream.read();
54
-
55
- if (done) {
56
- isClosed = true;
57
- break;
58
- }
59
- if (!event) continue;
60
-
61
- if (event.data === '[DONE]') {
62
- continue;
63
- }
64
-
65
- const json = JSON.parse(event.data);
66
-
67
- const { jsonrpc, id, result, meta, error } = json as JsonRpcResponse;
68
- await handleJsonrpcError({ status: res.status, json });
69
- const deserialized = superjson.deserialize({
70
- json: result,
71
- meta,
72
- });
73
- yield deserialized;
74
- }
75
- } finally {
76
- // if user calls return() in the generator, we need to close the stream
77
-
78
- if (!isClosed) {
79
- // if stream is still open, abort controller
80
- controller.abort();
81
- eventStream.cancel();
82
- }
83
- }
84
- };
85
-
86
- return generator;
87
- }
88
- async function rpcFetch(...args) {
89
- const { json: argsJson, meta } = superjson.serialize(args);
90
- const res = await fetch(url, {
91
- method: 'POST',
92
- body: JSON.stringify(
93
- {
94
- jsonrpc: '2.0',
95
- id: nextId++,
96
- method,
97
- params: argsJson as any[],
98
- meta,
99
- } satisfies JsonRpcRequest,
100
- null,
101
- 2,
102
- ),
103
- headers: {
104
- 'content-type': 'application/json',
105
- },
106
- });
107
- const json = await res.json();
108
- await handleJsonrpcError({ status: res.status, json });
109
- {
110
- const deserialized = superjson.deserialize({
111
- json: json.result,
112
- meta: json.meta,
113
- });
114
- return deserialized as any;
115
- }
116
- }
117
- rpcFetch.abort = function abort() {
118
- controller.abort();
119
- };
120
- return rpcFetch;
121
- }
122
-
123
- async function handleJsonrpcError({
124
- status,
125
- json,
126
- }: {
127
- status: number;
128
- json: JsonRpcResponse;
129
- }) {
130
- if (status >= 400) {
131
- const statusError = new Error('Unexpected HTTP status ' + status);
132
-
133
- if (json?.error && typeof json.error?.message === 'string') {
134
- let err = new Error(json.error.message);
135
- Object.assign(err, json.error.data || {});
136
- throw err;
137
- }
138
-
139
- throw statusError;
140
- }
141
- }