@output.ai/core 0.4.7 → 0.4.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@output.ai/core",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "description": "The core module of the output framework",
5
5
  "type": "module",
6
6
  "exports": {
@@ -3,7 +3,7 @@ import { proxyActivities, inWorkflowContext, executeChild, workflowInfo, uuid4,
3
3
  import { validateWorkflow } from './validations/static.js';
4
4
  import { validateWithSchema } from './validations/runtime.js';
5
5
  import { SHARED_STEP_PREFIX, ACTIVITY_GET_TRACE_DESTINATIONS, METADATA_ACCESS_SYMBOL } from '#consts';
6
- import { deepMerge, mergeActivityOptions, setMetadata } from '#utils';
6
+ import { deepMerge, mergeActivityOptions, setMetadata, toUrlSafeBase64 } from '#utils';
7
7
  import { FatalError, ValidationError } from '#errors';
8
8
 
9
9
  /**
@@ -121,7 +121,7 @@ export function workflow( { name, description, inputSchema, outputSchema, fn, op
121
121
  startWorkflow: async ( childName, input, extra = {} ) =>
122
122
  executeChild( childName, {
123
123
  args: input ? [ input ] : [],
124
- workflowId: `${workflowId}-${childName}-${uuid4()}`,
124
+ workflowId: `${workflowId}-${toUrlSafeBase64( uuid4() )}`,
125
125
  parentClosePolicy: ParentClosePolicy[extra?.detached ? 'ABANDON' : 'TERMINATE'],
126
126
  memo: {
127
127
  executionContext,
@@ -116,3 +116,12 @@ export function shuffleArray( arr: array ): array;
116
116
  * @returns A new merged object.
117
117
  */
118
118
  export function deepMerge( a: object, b: object ): object;
119
+
120
+ /**
121
+ * Shortens a UUID to a url-safe base64-like string (custom 64-char alphabet).
122
+ * Temporal-friendly: no Buffer or crypto; safe to use inside workflows.
123
+ *
124
+ * @param uuid - Standard UUID (e.g. `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`).
125
+ * @returns Short string using A–Z, a–z, 0–9, `_`, `-` (typically 21–22 chars).
126
+ */
127
+ export function toUrlSafeBase64( uuid: string ): string;
@@ -195,3 +195,20 @@ export const deepMerge = ( a, b ) => {
195
195
  Object.assign( obj, { [k]: isPlainObject( v ) && isPlainObject( a[k] ) ? deepMerge( a[k], v ) : v } )
196
196
  , clone( a ) );
197
197
  };
198
+
199
+ /**
200
+ * Shortens a UUID by re-encoding it to base62.
201
+ *
202
+ * This is a Temporal friendly, without crypto or Buffer.
203
+ * @param {string} uuid
204
+ * @returns {string}
205
+ */
206
+ export const toUrlSafeBase64 = uuid => {
207
+ const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-';
208
+ const alphabetLen = alphabet.length;
209
+ const base = BigInt( alphabetLen );
210
+ const hex = uuid.replace( /-/g, '' );
211
+
212
+ const toDigits = n => n <= 0n ? [] : toDigits( n / base ).concat( alphabet[Number( n % base )] );
213
+ return toDigits( BigInt( '0x' + hex ) ).join( '' );
214
+ };
@@ -1,6 +1,14 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { Readable } from 'node:stream';
3
- import { clone, mergeActivityOptions, serializeBodyAndInferContentType, serializeFetchResponse, deepMerge, isPlainObject } from './utils.js';
3
+ import {
4
+ clone,
5
+ mergeActivityOptions,
6
+ serializeBodyAndInferContentType,
7
+ serializeFetchResponse,
8
+ deepMerge,
9
+ isPlainObject,
10
+ toUrlSafeBase64
11
+ } from './utils.js';
4
12
 
5
13
  describe( 'clone', () => {
6
14
  it( 'produces a deep copy without shared references', () => {
@@ -411,3 +419,43 @@ describe( 'isPlainObject', () => {
411
419
  expect( isPlainObject( zum ) ).toBe( false );
412
420
  } );
413
421
  } );
422
+
423
+ describe( 'toUrlSafeBase64', () => {
424
+ const urlSafeAlphabet = /^[A-Za-z0-9_-]+$/;
425
+
426
+ it( 'returns a string for a valid UUID', () => {
427
+ const uuid = '550e8400-e29b-41d4-a716-446655440000';
428
+ expect( typeof toUrlSafeBase64( uuid ) ).toBe( 'string' );
429
+ expect( toUrlSafeBase64( uuid ).length ).toBeGreaterThan( 0 );
430
+ } );
431
+
432
+ it( 'output length is 21 or 22 for a standard UUID', () => {
433
+ const uuid = '550e8400-e29b-41d4-a716-446655440000';
434
+ const out = toUrlSafeBase64( uuid );
435
+ expect( out.length ).toBeGreaterThanOrEqual( 21 );
436
+ expect( out.length ).toBeLessThanOrEqual( 22 );
437
+ } );
438
+
439
+ it( 'output contains only url-safe alphabet characters', () => {
440
+ const uuid = '550e8400-e29b-41d4-a716-446655440000';
441
+ const out = toUrlSafeBase64( uuid );
442
+ expect( out ).toMatch( urlSafeAlphabet );
443
+ } );
444
+
445
+ it( 'is deterministic for the same UUID', () => {
446
+ const uuid = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
447
+ expect( toUrlSafeBase64( uuid ) ).toBe( toUrlSafeBase64( uuid ) );
448
+ } );
449
+
450
+ it( 'different UUIDs produce different strings', () => {
451
+ const a = toUrlSafeBase64( '550e8400-e29b-41d4-a716-446655440000' );
452
+ const b = toUrlSafeBase64( '6ba7b810-9dad-11d1-80b4-00c04fd430c8' );
453
+ expect( a ).not.toBe( b );
454
+ } );
455
+
456
+ it( 'strips hyphens and encodes hex (same as 32-char hex)', () => {
457
+ const withHyphens = '550e8400-e29b-41d4-a716-446655440000';
458
+ const hexOnly = '550e8400e29b41d4a716446655440000';
459
+ expect( toUrlSafeBase64( withHyphens ) ).toBe( toUrlSafeBase64( hexOnly ) );
460
+ } );
461
+ } );