@requence/service 1.0.0-alpha.51 → 1.0.0-alpha.53
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/CHANGELOG.md +12 -0
- package/README.md +235 -96
- package/build/cli.js +2 -1
- package/build/cli.js.map +3 -3
- package/build/index.js +69 -19
- package/build/index.js.map +6 -6
- package/build/types/helpers/src/files/RequenceFile.d.ts.map +1 -1
- package/build/types/helpers/src/files/RequenceStream.d.ts.map +1 -1
- package/build/types/helpers/src/files/isValidMimeType.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/NodeTree.d.ts +16 -2
- package/build/types/helpers/src/protocol/NodeTree.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/command.d.ts +26 -0
- package/build/types/helpers/src/protocol/command.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/nodeType.d.ts +10 -0
- package/build/types/helpers/src/protocol/nodeType.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/taskOptions.d.ts +3 -0
- package/build/types/helpers/src/protocol/taskOptions.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/templateNodeTypes.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/treeNodes.d.ts +38 -0
- package/build/types/helpers/src/protocol/treeNodes.d.ts.map +1 -1
- package/build/types/helpers/src/protocol/update.d.ts +23 -0
- package/build/types/helpers/src/protocol/update.d.ts.map +1 -1
- package/build/types/helpers/src/utils/callbackToAsyncIterator.d.ts +1 -1
- package/build/types/helpers/src/utils/callbackToAsyncIterator.d.ts.map +1 -1
- package/build/types/service/src/createAmqpConnection.d.ts +1 -1
- package/build/types/service/src/createAmqpConnection.d.ts.map +1 -1
- package/build/types/service/src/helpers.d.ts +6 -2
- package/build/types/service/src/helpers.d.ts.map +1 -1
- package/package.json +7 -3
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -1,191 +1,330 @@
|
|
|
1
|
-
# @requence/
|
|
1
|
+
# @requence/service
|
|
2
2
|
|
|
3
|
-
This package connects a
|
|
3
|
+
This package connects a TypeScript / Bun service to the Requence operator. It manages message retrieval, processing, and result delivery.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
```
|
|
8
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install @requence/service
|
|
9
|
+
```
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
## Authentication
|
|
12
|
+
|
|
13
|
+
Every service needs an **access token** to connect. Copy it from the **Services** list view in the Requence UI by clicking **Copy credentials**.
|
|
14
|
+
|
|
15
|
+
The token is resolved in this order:
|
|
16
|
+
|
|
17
|
+
1. `accessToken` option passed to `createService()`
|
|
18
|
+
2. `REQUENCE_SERVICE_ACCESS_TOKEN` or `REQUENCE_ACCESS_TOKEN` environment variable
|
|
19
|
+
3. `requence.service.accessToken` or `requence.accessToken` in `package.json`
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
REQUENCE_SERVICE_ACCESS_TOKEN=your-token bun run index.ts
|
|
13
23
|
```
|
|
14
24
|
|
|
15
|
-
|
|
16
|
-
To be more explicit about those configurations, you can pass an object as the first parameter:
|
|
25
|
+
## Usage
|
|
17
26
|
|
|
18
27
|
```typescript
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
(ctx) => {
|
|
25
|
-
return 'this is my response'
|
|
26
|
-
},
|
|
27
|
-
)
|
|
28
|
+
import { createService } from '@requence/service'
|
|
29
|
+
|
|
30
|
+
createService('1.0.0', (ctx) => {
|
|
31
|
+
return { message: `Hello, ${ctx.input.name}!` }
|
|
32
|
+
})
|
|
28
33
|
```
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
The second argument to `createService` is the **version** of the service definition you are implementing. When Requence dispatches a message, the handler runs and the return value is sent back as the result.
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
### Options object
|
|
38
|
+
|
|
39
|
+
Instead of a bare version string, you can pass an options object:
|
|
33
40
|
|
|
34
41
|
```typescript
|
|
35
|
-
|
|
42
|
+
import { createService } from '@requence/service'
|
|
43
|
+
|
|
44
|
+
createService(
|
|
36
45
|
{
|
|
37
|
-
|
|
46
|
+
version: '1.0.0',
|
|
47
|
+
prefetch: 5, // process up to 5 messages in parallel (default: 1)
|
|
48
|
+
connectionTimeout: 30_000, // ms to wait before throwing (default: 3000)
|
|
49
|
+
silent: false, // suppress lifecycle logs
|
|
38
50
|
},
|
|
39
51
|
async (ctx) => {
|
|
40
|
-
return
|
|
52
|
+
return processData(ctx.input)
|
|
41
53
|
},
|
|
42
54
|
)
|
|
43
55
|
```
|
|
44
56
|
|
|
45
|
-
|
|
57
|
+
### Return value
|
|
46
58
|
|
|
47
|
-
|
|
59
|
+
`createService` returns a `ServiceApi` object immediately (the connection is established in the background):
|
|
48
60
|
|
|
49
61
|
```typescript
|
|
50
|
-
const
|
|
62
|
+
const service = createService('1.0.0', handler)
|
|
51
63
|
|
|
52
|
-
//
|
|
53
|
-
|
|
64
|
+
// wait for the connection to be ready
|
|
65
|
+
await service.open()
|
|
66
|
+
|
|
67
|
+
// gracefully close the connection
|
|
68
|
+
await service.close()
|
|
54
69
|
```
|
|
55
70
|
|
|
56
|
-
|
|
71
|
+
## Context API
|
|
72
|
+
|
|
73
|
+
Every handler receives a `ctx` object.
|
|
57
74
|
|
|
58
|
-
|
|
75
|
+
### Data access
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
|
|
77
|
+
| Property | Description |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `ctx.input` | The input data routed to this service node from the task template |
|
|
80
|
+
| `ctx.configuration` | The static configuration set on the service node in the UI |
|
|
81
|
+
| `ctx.taskId` | The unique ID of the current task execution |
|
|
62
82
|
|
|
63
|
-
###
|
|
83
|
+
### Logging
|
|
84
|
+
|
|
85
|
+
`ctx.debug` sends log messages to the Requence UI in real time:
|
|
64
86
|
|
|
65
87
|
```typescript
|
|
66
|
-
ctx.
|
|
88
|
+
ctx.debug.log('Processing started')
|
|
89
|
+
ctx.debug.info('Step complete', { step: 1 })
|
|
90
|
+
ctx.debug.warn('Something looks off')
|
|
91
|
+
ctx.debug.error('An error occurred', error)
|
|
67
92
|
```
|
|
68
93
|
|
|
69
|
-
|
|
94
|
+
### Flow control
|
|
95
|
+
|
|
96
|
+
#### `ctx.retry(delay?)`
|
|
97
|
+
|
|
98
|
+
Instructs Requence to retry this service after an optional delay in milliseconds (minimum 100 ms). No code executes after this call.
|
|
70
99
|
|
|
71
100
|
```typescript
|
|
72
|
-
|
|
101
|
+
createService('1.0.0', async (ctx) => {
|
|
102
|
+
const db = await getDbConnection()
|
|
103
|
+
|
|
104
|
+
if (!db.isConnected) {
|
|
105
|
+
ctx.retry(2_000) // retry in 2 seconds
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return db.query('SELECT ...')
|
|
109
|
+
})
|
|
73
110
|
```
|
|
74
111
|
|
|
75
|
-
|
|
112
|
+
> **Note:** It is your responsibility to prevent infinite retry loops.
|
|
113
|
+
|
|
114
|
+
#### `ctx.abort(reason?)`
|
|
115
|
+
|
|
116
|
+
Instructs Requence to abort this service immediately. If the service node's **on fail** output is not connected, the entire task fails.
|
|
76
117
|
|
|
77
118
|
```typescript
|
|
78
|
-
|
|
119
|
+
createService('1.0.0', (ctx) => {
|
|
120
|
+
if (!ctx.input.requiredField) {
|
|
121
|
+
ctx.abort('Missing required field')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return processData(ctx.input)
|
|
125
|
+
})
|
|
79
126
|
```
|
|
80
127
|
|
|
81
|
-
|
|
128
|
+
#### `ctx.skip()`
|
|
129
|
+
|
|
130
|
+
Puts the message back on the queue without processing it. The next available service instance will receive it instead.
|
|
131
|
+
|
|
132
|
+
#### `ctx.toOutput(name, value)`
|
|
133
|
+
|
|
134
|
+
Routes the result to a specific **named output** on the service node. Use this when your service definition has multiple outputs:
|
|
82
135
|
|
|
83
136
|
```typescript
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
137
|
+
createService('1.0.0', (ctx) => {
|
|
138
|
+
if (ctx.input.type === 'pdf') {
|
|
139
|
+
return ctx.toOutput('pdf', { url: '...' })
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return ctx.toOutput('other', { raw: ctx.input })
|
|
143
|
+
})
|
|
92
144
|
```
|
|
93
145
|
|
|
94
|
-
|
|
146
|
+
#### `ctx.defer(reason?)`
|
|
147
|
+
|
|
148
|
+
Marks the message as **deferred**. The service acknowledges the message but signals that the result will be delivered later via `service.act()`. Returns a **message key** that you must store and pass to `act()`:
|
|
95
149
|
|
|
96
150
|
```typescript
|
|
97
|
-
|
|
151
|
+
createService('1.0.0', (ctx) => {
|
|
152
|
+
const messageKey = ctx.defer('waiting for external process')
|
|
153
|
+
externalQueue.push({ messageKey, payload: ctx.input })
|
|
154
|
+
// handler returns — message is held open until act() is called
|
|
155
|
+
})
|
|
98
156
|
```
|
|
99
157
|
|
|
100
|
-
|
|
158
|
+
#### `ctx.terminated`
|
|
159
|
+
|
|
160
|
+
A `Promise` that resolves when the task is stopped (cancelled via the UI or API, or terminated by another node). Use it in continuous/generator services to know when to stop producing values.
|
|
161
|
+
|
|
162
|
+
`ctx.terminated.signal` is a native [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that fires at the same moment — pass it to any abort-aware API:
|
|
101
163
|
|
|
102
164
|
```typescript
|
|
103
|
-
|
|
165
|
+
import { setTimeout } from 'node:timers/promises'
|
|
166
|
+
import { createService } from '@requence/service'
|
|
167
|
+
|
|
168
|
+
// Poll every 5 seconds, exit immediately when the task is stopped
|
|
169
|
+
createService('1.0.0', async function* (ctx) {
|
|
170
|
+
while (true) {
|
|
171
|
+
await setTimeout(5_000, null, { signal: ctx.terminated.signal })
|
|
172
|
+
yield await pollForUpdates()
|
|
173
|
+
}
|
|
174
|
+
})
|
|
104
175
|
```
|
|
105
176
|
|
|
106
|
-
|
|
177
|
+
Or race against it directly:
|
|
107
178
|
|
|
108
179
|
```typescript
|
|
109
|
-
|
|
180
|
+
const result = await Promise.race([
|
|
181
|
+
fetchData(),
|
|
182
|
+
ctx.terminated,
|
|
183
|
+
])
|
|
110
184
|
```
|
|
111
185
|
|
|
112
|
-
The
|
|
186
|
+
> The framework automatically catches the `AbortError` thrown by abort-aware APIs when the task is terminated — no `try/catch` needed inside a generator.
|
|
187
|
+
|
|
188
|
+
## Continuous (Generator) Mode
|
|
189
|
+
|
|
190
|
+
When a service node is configured in **continuous mode**, the handler can be an async generator. Each `yield` sends an incremental result to Requence; the final `return` (or generator completion) signals the end of processing:
|
|
113
191
|
|
|
114
192
|
```typescript
|
|
115
|
-
|
|
193
|
+
createService('1.0.0', async function* (ctx) {
|
|
194
|
+
for (const chunk of await fetchChunks(ctx.input)) {
|
|
195
|
+
yield { chunk }
|
|
196
|
+
}
|
|
197
|
+
})
|
|
116
198
|
```
|
|
117
199
|
|
|
118
|
-
|
|
200
|
+
The generator is terminated automatically when `ctx.terminated` resolves. Yielded values are still sent before the generator exits.
|
|
201
|
+
|
|
202
|
+
## Deferred Delivery via `service.act()`
|
|
203
|
+
|
|
204
|
+
After deferring a message with `ctx.defer()`, use `service.act()` to deliver the result later — even from a different process run:
|
|
119
205
|
|
|
120
206
|
```typescript
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
207
|
+
const service = createService('1.0.0', (ctx) => {
|
|
208
|
+
const messageKey = ctx.defer()
|
|
209
|
+
saveMessageKey(ctx.taskId, messageKey)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
// ... in a webhook handler or background job:
|
|
213
|
+
await service.act(messageKey, async (api) => {
|
|
214
|
+
api.send({ result: 'done' })
|
|
215
|
+
// or: api.sendToOutput('success', { result: 'done' })
|
|
216
|
+
// or: api.abort('something went wrong')
|
|
217
|
+
})
|
|
131
218
|
```
|
|
132
219
|
|
|
133
|
-
|
|
220
|
+
`act()` also supports returning a value or an iterable directly from the actor function, which behaves the same as calling `api.send()` for each value.
|
|
221
|
+
|
|
222
|
+
## Dev Overlay
|
|
223
|
+
|
|
224
|
+
When developing locally alongside a production service, use a **dev token** (your personal access token) to register a dev instance. Requence routes your own tasks to the dev instance instead of the production pool:
|
|
134
225
|
|
|
135
226
|
```typescript
|
|
136
|
-
|
|
227
|
+
import { createService } from '@requence/service'
|
|
228
|
+
|
|
229
|
+
createService(
|
|
230
|
+
{
|
|
231
|
+
version: '1.0.0',
|
|
232
|
+
devToken: process.env.REQUENCE_DEV_TOKEN,
|
|
233
|
+
},
|
|
234
|
+
(ctx) => ctx.input,
|
|
235
|
+
)
|
|
137
236
|
```
|
|
138
237
|
|
|
139
|
-
The
|
|
238
|
+
The dev token is resolved in the same order as the access token — option, `REQUENCE_SERVICE_DEV_TOKEN` / `REQUENCE_DEV_TOKEN` env var, or `requence.service.devToken` / `requence.devToken` in `package.json`.
|
|
140
239
|
|
|
141
|
-
|
|
240
|
+
## CLI — Generate Types
|
|
142
241
|
|
|
143
|
-
|
|
144
|
-
|
|
242
|
+
The package ships with a CLI that generates TypeScript types derived from the schemas you defined in the Requence UI (input, configuration, and outputs):
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
npx requence-service generate-types
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
This creates a `requence-env.d.ts` file in your project root. TypeScript picks it up automatically — `ctx.input`, `ctx.configuration`, and `ctx.toOutput()` calls become fully typed.
|
|
249
|
+
|
|
250
|
+
### Options
|
|
251
|
+
|
|
252
|
+
| Option | Default | Description |
|
|
253
|
+
|---|---|---|
|
|
254
|
+
| `--access-token` | — | Service access token (falls back to env / config file) |
|
|
255
|
+
| `--dev-token` | — | Personal access token for branch-specific types |
|
|
256
|
+
| `--outfile` | `requence-env.d.ts` | Name of the generated type file |
|
|
257
|
+
| `--outdir` | `.` | Directory to write the type file to |
|
|
258
|
+
| `--watch` | `false` | Watch for schema changes and regenerate automatically |
|
|
259
|
+
| `--clear` / `--no-clear` | `true` | Clear the terminal on watch updates |
|
|
260
|
+
|
|
261
|
+
### Watch mode
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
npx requence-service generate-types --watch
|
|
145
265
|
```
|
|
146
266
|
|
|
147
|
-
|
|
148
|
-
|
|
267
|
+
The CLI connects via server-sent events and regenerates types whenever a schema changes in the UI.
|
|
268
|
+
|
|
269
|
+
## Utility Helpers
|
|
270
|
+
|
|
271
|
+
### `wrapIterable(iterable)`
|
|
272
|
+
|
|
273
|
+
Wraps any `Iterable` or `AsyncIterable` so that iteration stops automatically when `ctx.terminated` resolves:
|
|
149
274
|
|
|
150
275
|
```typescript
|
|
151
|
-
|
|
276
|
+
import { wrapIterable } from '@requence/service'
|
|
277
|
+
|
|
278
|
+
createService('1.0.0', async function* (ctx) {
|
|
279
|
+
for await (const event of wrapIterable(eventStream)) {
|
|
280
|
+
yield processEvent(event)
|
|
281
|
+
}
|
|
282
|
+
})
|
|
152
283
|
```
|
|
153
284
|
|
|
154
|
-
|
|
155
|
-
If the service is not configured with a fail over, the complete task will fail.
|
|
285
|
+
### `asyncEventEmitter(initial?)`
|
|
156
286
|
|
|
157
|
-
|
|
287
|
+
Creates an async-iterable event emitter that integrates with `ctx.terminated`. Push values from outside (e.g. callbacks or event listeners) and iterate them inside the generator:
|
|
158
288
|
|
|
159
|
-
|
|
289
|
+
```typescript
|
|
290
|
+
import { asyncEventEmitter, createService } from '@requence/service'
|
|
160
291
|
|
|
161
|
-
|
|
292
|
+
createService('1.0.0', async function* (ctx) {
|
|
293
|
+
const emitter = asyncEventEmitter<string>()
|
|
162
294
|
|
|
163
|
-
|
|
295
|
+
externalSource.on('data', (value) => emitter.push(value))
|
|
296
|
+
|
|
297
|
+
for await (const value of emitter) {
|
|
298
|
+
yield { value }
|
|
299
|
+
}
|
|
300
|
+
})
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
The iterator exits automatically when the task is terminated.
|
|
304
|
+
|
|
305
|
+
## Full Example
|
|
164
306
|
|
|
165
307
|
```typescript
|
|
166
|
-
import
|
|
167
|
-
import db from './database.js'
|
|
168
|
-
|
|
308
|
+
import { createService } from '@requence/service'
|
|
309
|
+
import { db } from './database.js'
|
|
310
|
+
|
|
311
|
+
createService(
|
|
169
312
|
{
|
|
170
|
-
url: 'amqp://username:password@host',
|
|
171
313
|
version: '1.2.3',
|
|
172
|
-
prefetch: 2, //
|
|
314
|
+
prefetch: 2, // process 2 messages in parallel
|
|
173
315
|
},
|
|
174
316
|
async (ctx) => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (!ocrData) {
|
|
178
|
-
ctx.abort('Ocr service is mandatory for this AI service')
|
|
317
|
+
if (!db.isConnected) {
|
|
318
|
+
ctx.retry(2_000) // wait 2s for the DB to recover
|
|
179
319
|
}
|
|
180
320
|
|
|
181
|
-
if (!
|
|
182
|
-
|
|
183
|
-
ctx.retry(2000)
|
|
321
|
+
if (!ctx.input.ocrData) {
|
|
322
|
+
ctx.abort('OCR data is mandatory')
|
|
184
323
|
}
|
|
185
324
|
|
|
186
|
-
const
|
|
325
|
+
const result = await db.getDataBasedOnOcr(ctx.input.ocrData)
|
|
187
326
|
|
|
188
|
-
return
|
|
327
|
+
return result
|
|
189
328
|
},
|
|
190
329
|
)
|
|
191
330
|
```
|
package/build/cli.js
CHANGED
|
@@ -56,6 +56,7 @@ async function fetchTypes(url, headers, targetFile, clear = false, showTimestamp
|
|
|
56
56
|
`;
|
|
57
57
|
}
|
|
58
58
|
const data = `${header}/* eslint-disable */
|
|
59
|
+
/* oxlint-disable */
|
|
59
60
|
/* prettier-ignore */
|
|
60
61
|
|
|
61
62
|
${text}`;
|
|
@@ -156,5 +157,5 @@ in your ${chalk.bold("package.json")} in ${chalk.bold("requence.accessToken")} /
|
|
|
156
157
|
});
|
|
157
158
|
}).scriptName("requence-service").help("h").demandCommand(1, 1).strict().parse();
|
|
158
159
|
|
|
159
|
-
//# debugId=
|
|
160
|
+
//# debugId=F3C67DF0D72FBC3064756E2164756E21
|
|
160
161
|
//# sourceMappingURL=cli.js.map
|
package/build/cli.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cli.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"#!/usr/bin/env node\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { deobfuscate } from '@requence/helpers'\nimport chalk from 'chalk'\nimport { createEventSource } from 'eventsource-client'\nimport yargs from 'yargs'\nimport { hideBin } from 'yargs/helpers'\nimport { z } from 'zod/v4'\n\nconst y = yargs(hideBin(process.argv))\n\nconst colors = {\n red: chalk.hex('#ef4444'),\n green: chalk.hex('#22c55e'),\n yellow: chalk.hex('#eab308'),\n orange: chalk.hex('#f97316'),\n zinc: chalk.hex('#71717a'),\n}\n\nfunction errorExit(title: string, text?: string): never {\n console.error(colors.red.bold(title + '\\n'))\n if (text) {\n console.error(colors.red(text) + '\\n')\n }\n process.exit(1)\n}\n\nlet pkgJson: any | null\nfunction loadPkgJson() {\n if (!pkgJson) {\n pkgJson = JSON.parse(fs.readFileSync('package.json', 'utf-8'))\n }\n return pkgJson\n}\n\nasync function fetchTypes(\n url: string,\n headers: HeadersInit,\n targetFile: string,\n clear = false,\n showTimestamp = false,\n) {\n const timestamp = () =>\n colors.zinc(new Date().toLocaleTimeString('en-GB', { hour12: false }))\n const response = await fetch(url, {\n method: 'GET',\n headers,\n })\n\n const branchName = response.headers.get('x-branch-name')\n const text = await response.text()\n\n if (!response.ok) {\n errorExit(text)\n }\n\n let header =\n '// Generated by requence-service CLI — DO NOT EDIT.\\n// Changes will be overwritten.\\n\\n'\n\n if (branchName) {\n header += `// !!! types for branch \"${branchName}\" !!!\\n\\n`\n }\n const data = `${header}/* eslint-disable */\\n/* prettier-ignore */\\n\\n${text}`\n\n fs.writeFileSync(targetFile, data)\n\n if (clear) {\n console.clear()\n }\n\n if (branchName) {\n console.info(\n ...(showTimestamp ? [timestamp()] : []),\n colors.yellow(\n 'types for branch',\n chalk.bold(branchName),\n 'saved to',\n chalk.bold(path.relative(process.cwd(), targetFile)),\n ),\n )\n } else {\n console.info(\n ...(showTimestamp ? [timestamp()] : []),\n colors.green(\n 'types saved to',\n chalk.bold(path.relative(process.cwd(), targetFile)),\n ),\n )\n }\n}\n\ny.command(\n 'generate-types',\n 'generates typescript types',\n (yargs) =>\n yargs\n .option('access-token', {\n describe: 'access token',\n type: 'string',\n })\n .option('dev-token', {\n description: 'dev token',\n type: 'string',\n })\n .option('outfile', {\n default: 'requence-env.d.ts',\n })\n .option('outdir', {\n default: '',\n })\n .option('watch', {\n type: 'boolean',\n })\n .option('clear', {\n description:\n 'clear the terminal on watch updates (use --no-clear to disable)',\n type: 'boolean',\n default: true,\n }),\n async (argv) => {\n let token =\n argv.accessToken ??\n process.env.REQUENCE_SERVICE_ACCESS_TOKEN ??\n process.env.REQUENCE_ACCESS_TOKEN\n\n if (!token) {\n const pkgJson = loadPkgJson()\n token =\n pkgJson.requence?.service?.accessToken ?? pkgJson.requence?.accessToken\n }\n\n if (argv.clear) {\n console.info() // newline\n }\n if (!token) {\n errorExit(\n 'No access token found',\n `You can provide the access token as argument to ${chalk.bold('requence-service')},\\nas environment variable ${chalk.bold('REQUENCE_ACCESS_TOKEN')} / ${chalk.bold('REQUENCE_SERVICE_ACCESS_TOKEN')} or\\nin your ${chalk.bold('package.json')} in ${chalk.bold('requence.accessToken')} / ${chalk.bold('requence.service.accessToken')}`,\n )\n }\n\n const parts = deobfuscate(token)\n if (parts.length !== 3 || parts[0] !== 'service') {\n errorExit('Invalid service key')\n }\n\n const [, connectionString, serverUrl] = parts\n const headers: HeadersInit = {\n Authorization: `Bearer ${connectionString}`,\n }\n let devToken =\n argv.devToken ??\n process.env.REQUENCE_SERVICE_ACCESS_TOKEN ??\n process.env.REQUENCE_ACCESS_TOKEN\n\n if (!devToken) {\n const pkgJson = loadPkgJson()\n devToken =\n pkgJson.requence?.service?.devToken ?? pkgJson.requence?.devToken\n }\n\n if (devToken) {\n const devParts = deobfuscate(devToken)\n if (devParts[0] !== 'api') {\n throw new Error(\n 'invalid dev token: please provide a personal access token',\n )\n }\n if (devParts[2] !== parts[2]) {\n throw new Error(\n 'invalid dev token: access token and dev token belong to different requence instances',\n )\n }\n\n headers['x-dev-authorization'] = devParts[1]\n }\n\n await fetchTypes(\n serverUrl + '/service/types/typescript',\n headers,\n path.join(argv.outdir || process.cwd(), argv.outfile),\n )\n\n if (!argv.watch) {\n return\n }\n\n if (argv.clear) {\n console.clear()\n }\n console.info(colors.orange.bold('Watching for type changes…'))\n let lastWrite = Date.now()\n const timeSchema = z.coerce.number().int().positive()\n createEventSource({\n method: 'GET',\n url: serverUrl + '/service/watch',\n headers,\n async onMessage({ data }) {\n const timeResult = timeSchema.safeParse(data)\n if (!timeResult.success || timeResult.data < lastWrite) {\n return\n }\n lastWrite = timeResult.data\n if (argv.clear) {\n console.clear()\n }\n console.info(\n colors.zinc.bold(`Regenerating types…${argv.clear ? '\\n\\n' : ''}`),\n )\n\n await fetchTypes(\n serverUrl + '/service/types/typescript',\n headers,\n path.join(argv.outdir || process.cwd(), argv.outfile),\n argv.clear,\n true,\n )\n console.info(\n colors.orange.bold(\n `${argv.clear ? '\\n\\n' : ''}Watching for type changes…`,\n ),\n )\n },\n })\n },\n)\n .scriptName('requence-service')\n .help('h')\n .demandCommand(1, 1)\n .strict()\n .parse()\n"
|
|
5
|
+
"#!/usr/bin/env node\n\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { deobfuscate } from '@requence/helpers'\nimport chalk from 'chalk'\nimport { createEventSource } from 'eventsource-client'\nimport yargs from 'yargs'\nimport { hideBin } from 'yargs/helpers'\nimport { z } from 'zod/v4'\n\nconst y = yargs(hideBin(process.argv))\n\nconst colors = {\n red: chalk.hex('#ef4444'),\n green: chalk.hex('#22c55e'),\n yellow: chalk.hex('#eab308'),\n orange: chalk.hex('#f97316'),\n zinc: chalk.hex('#71717a'),\n}\n\nfunction errorExit(title: string, text?: string): never {\n console.error(colors.red.bold(title + '\\n'))\n if (text) {\n console.error(colors.red(text) + '\\n')\n }\n process.exit(1)\n}\n\nlet pkgJson: any | null\nfunction loadPkgJson() {\n if (!pkgJson) {\n pkgJson = JSON.parse(fs.readFileSync('package.json', 'utf-8'))\n }\n return pkgJson\n}\n\nasync function fetchTypes(\n url: string,\n headers: HeadersInit,\n targetFile: string,\n clear = false,\n showTimestamp = false,\n) {\n const timestamp = () =>\n colors.zinc(new Date().toLocaleTimeString('en-GB', { hour12: false }))\n const response = await fetch(url, {\n method: 'GET',\n headers,\n })\n\n const branchName = response.headers.get('x-branch-name')\n const text = await response.text()\n\n if (!response.ok) {\n errorExit(text)\n }\n\n let header =\n '// Generated by requence-service CLI — DO NOT EDIT.\\n// Changes will be overwritten.\\n\\n'\n\n if (branchName) {\n header += `// !!! types for branch \"${branchName}\" !!!\\n\\n`\n }\n const data = `${header}/* eslint-disable */\\n/* oxlint-disable */\\n/* prettier-ignore */\\n\\n${text}`\n\n fs.writeFileSync(targetFile, data)\n\n if (clear) {\n console.clear()\n }\n\n if (branchName) {\n console.info(\n ...(showTimestamp ? [timestamp()] : []),\n colors.yellow(\n 'types for branch',\n chalk.bold(branchName),\n 'saved to',\n chalk.bold(path.relative(process.cwd(), targetFile)),\n ),\n )\n } else {\n console.info(\n ...(showTimestamp ? [timestamp()] : []),\n colors.green(\n 'types saved to',\n chalk.bold(path.relative(process.cwd(), targetFile)),\n ),\n )\n }\n}\n\ny.command(\n 'generate-types',\n 'generates typescript types',\n (yargs) =>\n yargs\n .option('access-token', {\n describe: 'access token',\n type: 'string',\n })\n .option('dev-token', {\n description: 'dev token',\n type: 'string',\n })\n .option('outfile', {\n default: 'requence-env.d.ts',\n })\n .option('outdir', {\n default: '',\n })\n .option('watch', {\n type: 'boolean',\n })\n .option('clear', {\n description:\n 'clear the terminal on watch updates (use --no-clear to disable)',\n type: 'boolean',\n default: true,\n }),\n async (argv) => {\n let token =\n argv.accessToken ??\n process.env.REQUENCE_SERVICE_ACCESS_TOKEN ??\n process.env.REQUENCE_ACCESS_TOKEN\n\n if (!token) {\n const pkgJson = loadPkgJson()\n token =\n pkgJson.requence?.service?.accessToken ?? pkgJson.requence?.accessToken\n }\n\n if (argv.clear) {\n console.info() // newline\n }\n if (!token) {\n errorExit(\n 'No access token found',\n `You can provide the access token as argument to ${chalk.bold('requence-service')},\\nas environment variable ${chalk.bold('REQUENCE_ACCESS_TOKEN')} / ${chalk.bold('REQUENCE_SERVICE_ACCESS_TOKEN')} or\\nin your ${chalk.bold('package.json')} in ${chalk.bold('requence.accessToken')} / ${chalk.bold('requence.service.accessToken')}`,\n )\n }\n\n const parts = deobfuscate(token)\n if (parts.length !== 3 || parts[0] !== 'service') {\n errorExit('Invalid service key')\n }\n\n const [, connectionString, serverUrl] = parts\n const headers: HeadersInit = {\n Authorization: `Bearer ${connectionString}`,\n }\n let devToken =\n argv.devToken ??\n process.env.REQUENCE_SERVICE_ACCESS_TOKEN ??\n process.env.REQUENCE_ACCESS_TOKEN\n\n if (!devToken) {\n const pkgJson = loadPkgJson()\n devToken =\n pkgJson.requence?.service?.devToken ?? pkgJson.requence?.devToken\n }\n\n if (devToken) {\n const devParts = deobfuscate(devToken)\n if (devParts[0] !== 'api') {\n throw new Error(\n 'invalid dev token: please provide a personal access token',\n )\n }\n if (devParts[2] !== parts[2]) {\n throw new Error(\n 'invalid dev token: access token and dev token belong to different requence instances',\n )\n }\n\n headers['x-dev-authorization'] = devParts[1]\n }\n\n await fetchTypes(\n serverUrl + '/service/types/typescript',\n headers,\n path.join(argv.outdir || process.cwd(), argv.outfile),\n )\n\n if (!argv.watch) {\n return\n }\n\n if (argv.clear) {\n console.clear()\n }\n console.info(colors.orange.bold('Watching for type changes…'))\n let lastWrite = Date.now()\n const timeSchema = z.coerce.number().int().positive()\n createEventSource({\n method: 'GET',\n url: serverUrl + '/service/watch',\n headers,\n async onMessage({ data }) {\n const timeResult = timeSchema.safeParse(data)\n if (!timeResult.success || timeResult.data < lastWrite) {\n return\n }\n lastWrite = timeResult.data\n if (argv.clear) {\n console.clear()\n }\n console.info(\n colors.zinc.bold(`Regenerating types…${argv.clear ? '\\n\\n' : ''}`),\n )\n\n await fetchTypes(\n serverUrl + '/service/types/typescript',\n headers,\n path.join(argv.outdir || process.cwd(), argv.outfile),\n argv.clear,\n true,\n )\n console.info(\n colors.orange.bold(\n `${argv.clear ? '\\n\\n' : ''}Watching for type changes…`,\n ),\n )\n },\n })\n },\n)\n .scriptName('requence-service')\n .help('h')\n .demandCommand(1, 1)\n .strict()\n .parse()\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;AAEA;AACA;AAGA;AACA;AACA;AACA;AACA;AAEA,IAAM,IAAI,MAAM,QAAQ,QAAQ,IAAI,CAAC;AAErC,IAAM,SAAS;AAAA,EACb,KAAK,MAAM,IAAI,SAAS;AAAA,EACxB,OAAO,MAAM,IAAI,SAAS;AAAA,EAC1B,QAAQ,MAAM,IAAI,SAAS;AAAA,EAC3B,QAAQ,MAAM,IAAI,SAAS;AAAA,EAC3B,MAAM,MAAM,IAAI,SAAS;AAC3B;AAEA,SAAS,SAAS,CAAC,OAAe,MAAsB;AAAA,EACtD,QAAQ,MAAM,OAAO,IAAI,KAAK,QAAQ;AAAA,CAAI,CAAC;AAAA,EAC3C,IAAI,MAAM;AAAA,IACR,QAAQ,MAAM,OAAO,IAAI,IAAI,IAAI;AAAA,CAAI;AAAA,EACvC;AAAA,EACA,QAAQ,KAAK,CAAC;AAAA;AAGhB,IAAI;AACJ,SAAS,WAAW,GAAG;AAAA,EACrB,KAAK,SAAS;AAAA,IACZ,UAAU,KAAK,MAAM,GAAG,aAAa,gBAAgB,OAAO,CAAC;AAAA,EAC/D;AAAA,EACA,OAAO;AAAA;AAGT,eAAe,UAAU,CACvB,KACA,SACA,YACA,QAAQ,OACR,gBAAgB,OAChB;AAAA,EACA,MAAM,YAAY,MAChB,OAAO,KAAK,IAAI,KAAK,EAAE,mBAAmB,SAAS,EAAE,QAAQ,MAAM,CAAC,CAAC;AAAA,EACvE,MAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAAA,EAED,MAAM,aAAa,SAAS,QAAQ,IAAI,eAAe;AAAA,EACvD,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,EAEjC,KAAK,SAAS,IAAI;AAAA,IAChB,UAAU,IAAI;AAAA,EAChB;AAAA,EAEA,IAAI,SACF;AAAA;AAAA;AAAA;AAAA,EAEF,IAAI,YAAY;AAAA,IACd,UAAU,4BAA4B;AAAA;AAAA;AAAA,EACxC;AAAA,EACA,MAAM,OAAO,GAAG;AAAA;AAAA;AAAA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "F3C67DF0D72FBC3064756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|