@funnelchat-hq/sandbox 0.1.1 → 0.3.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/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { ConfigError, parseArgs, VERSION, DEFAULT_PORT, DEFAULT_CONFIG_FILE, resolveConfig, createSandbox } from './chunk-KH6A3I2A.js';
2
+ import { ConfigError, parseArgs, VERSION, DEFAULT_PORT, DEFAULT_CONFIG_FILE, resolveConfig, createSandbox } from './chunk-PCGMUC35.js';
3
3
 
4
4
  // src/cli.ts
5
5
  var HELP = `funnelchat-sandbox ${VERSION}
@@ -10,6 +10,7 @@ Usage: npx funnelchat-sandbox [options]
10
10
  Options:
11
11
  -p, --port <n> Port (default ${DEFAULT_PORT}; 0 takes a free one).
12
12
  --host <host> Where to listen (default 127.0.0.1; in Docker, 0.0.0.0).
13
+ --public-url <url> Base URL of the sign-up links (default: where it listens; in Docker, the published one).
13
14
  -c, --config <file> JSON configuration (default ./${DEFAULT_CONFIG_FILE}, if it exists).
14
15
  --status-delays <s,d,r> Seconds until sent, delivered and read (default 1,2,3; "-" stops there).
15
16
  --retry-delays <a,b,c> Seconds between retries of a webhook (default 60,300,1800).
@@ -19,6 +20,8 @@ Options:
19
20
  --no-antiblock Do not apply the spam brakes.
20
21
  --no-rate-limit Do not apply the per-number pace.
21
22
  --template-approval <s> Seconds until a new template is approved (default 5; "-" leaves it pending).
23
+ --meta-connect Turn on the Meta sign-up by link (off by default, like production).
24
+ --no-group-actions Turn off the send to a group by API (on by default, like production).
22
25
  -q, --quiet No line per request and per delivery.
23
26
  -h, --help This help.
24
27
  -v, --version The version.
package/dist/index.d.ts CHANGED
@@ -10,6 +10,12 @@ interface PresetSubscription {
10
10
  /** Optional: a fixed id (UUID). */
11
11
  id?: string;
12
12
  }
13
+ /** A workspace created at start (and after every reset) besides the default one, with fixed keys. */
14
+ interface PresetWorkspace {
15
+ name: string;
16
+ /** Keys of that workspace (`<id>|fc_live_<letters and digits>`). Any other key belongs to the default workspace. */
17
+ keys: string[];
18
+ }
13
19
  interface SandboxConfig {
14
20
  port: number;
15
21
  host: string;
@@ -39,8 +45,40 @@ interface SandboxConfig {
39
45
  };
40
46
  /** Seconds until a template created through the API goes from `PENDING` to `APPROVED`. `null`: it stays pending. */
41
47
  templateApprovalSeconds: number | null;
42
- /** Subscriptions to create at start and after every reset. */
48
+ /** Subscriptions to create at start and after every reset, in the default workspace. */
43
49
  subscriptions: PresetSubscription[];
50
+ /** Workspaces to create at start and after every reset, besides the default one (ids 2, 3… in this order). */
51
+ workspaces: PresetWorkspace[];
52
+ /**
53
+ * The number quota of the account and the Meta sign-up switch; `POST /_sandbox/numbers` changes them while it runs.
54
+ * QR and Meta of the same phone count once; the two example numbers already use two places.
55
+ */
56
+ numbers: {
57
+ /** Numbers the plan allows: `403 number_limit_reached` beyond it. */
58
+ limit: number;
59
+ /** `false`: the plan has no numbers, `403 numbers_not_included`. */
60
+ included: boolean;
61
+ /** A trial account: one number of the US pool instead of three. */
62
+ trial: boolean;
63
+ /**
64
+ * The Meta sign-up by link. `false` (the default, like production until the domain is registered with Meta):
65
+ * `POST /connect-links` with `type: meta` and its page answer `503 meta_connect_disabled`. Turn it on to test it.
66
+ */
67
+ metaConnect: boolean;
68
+ /** `POST /connect-links` per minute (accounts: 10); one more answers Laravel's `429 Too Many Attempts.`. */
69
+ linksPerMinute: number;
70
+ };
71
+ /**
72
+ * The group actions by API (`POST /groups/{group}/messages`, `GET /groups/actions/{action}`). `true` (the default,
73
+ * like production, where communities' kill switch `API_GROUP_ACTIONS_ENABLED` is on). `false` imitates the switch
74
+ * off: every key gets `403 route_not_available`.
75
+ */
76
+ groupActions: boolean;
77
+ /**
78
+ * Where the sign-up page is reachable, for the `url` of a link (`<publicUrl>/connect/<token>`). Never taken from the
79
+ * request's `Host`. `null`: the address the sandbox listens on.
80
+ */
81
+ publicUrl: string | null;
44
82
  /** How many requests and deliveries the panel keeps. */
45
83
  historyLimit: number;
46
84
  /** One line per request and per delivery on the console. */
@@ -60,21 +98,84 @@ interface MessageError {
60
98
  reason: string | null;
61
99
  }
62
100
  type DeviceKind = 'cloud' | 'qr';
101
+ /** The aggregated health of an official number (accounts `MetaHealthStatusService`). */
102
+ type HealthState = 'available' | 'limited' | 'blocked' | 'unknown';
103
+ /**
104
+ * A workspace of the account (accounts `workspaces`). Every API key belongs to one and only sees and creates there
105
+ * (accounts v1.5.97, workspaces-api-keys). What has no workspace (`null`) counts as the default one's.
106
+ */
107
+ interface Workspace {
108
+ id: number;
109
+ name: string;
110
+ isDefault: boolean;
111
+ createdAt: Date;
112
+ }
63
113
  interface Device {
64
114
  id: number;
115
+ /** The workspace the number is in; `null` counts as the default one. */
116
+ workspaceId: number | null;
65
117
  alias: string;
66
- /** Digits only, without `+`. */
67
- number: string;
118
+ /** Digits only, without `+`. `null` while a number created by QR has not been scanned. */
119
+ number: string | null;
68
120
  /** WhatsAppProviderEnum of accounts: 1 Z-API (QR), 2 WhatsApp Cloud (official). */
69
121
  provider: 1 | 2;
70
122
  kind: DeviceKind;
71
123
  connected: boolean;
124
+ /** Official numbers only: it shares the number with the WhatsApp Business app. */
125
+ coexistence: boolean;
126
+ /** Official numbers only: it came from the pool of US numbers. */
127
+ fromPool: boolean;
128
+ /** Free text of the integrator, up to 255 characters, not unique. */
129
+ externalReference: string | null;
130
+ /** Official numbers only (`null` for QR). */
131
+ health: HealthState | null;
132
+ /** The sign-up link that connected it last: `connect_link_id` of every `device.*` event. */
133
+ lastConnectLinkId: number | null;
72
134
  wabaId: string | null;
73
135
  phoneNumberId: string | null;
136
+ firstConnectedAt: Date | null;
74
137
  createdAt: Date;
75
138
  }
139
+ type ConnectLinkStatus = 'pending' | 'completed' | 'failed' | 'expired' | 'revoked';
140
+ /** A sign-up link (contract A1 `connect-links`): it creates (or reconnects) a number when the page completes. */
141
+ interface ConnectLink {
142
+ id: number;
143
+ /** The workspace of the key that created it: the number it creates lands there. */
144
+ workspaceId: number | null;
145
+ type: 'meta' | 'qr';
146
+ status: ConnectLinkStatus;
147
+ /** sha256 of the token: the raw token is only in the `url` of the create answer. */
148
+ tokenHash: string;
149
+ allowedConnectionTypes: ('coexistence' | 'dedicated')[] | null;
150
+ provisionUsNumber: boolean;
151
+ /** `qr` only, without `device_id`: the country of the phone (two letters, lower case), where the session opens. */
152
+ country: string | null;
153
+ /** Reconnects this number; otherwise `null` until the link completes, then the number it created. */
154
+ deviceId: number | null;
155
+ reconnect: boolean;
156
+ /** `qr` only: adds QR to this number in coexistence. Not part of the public resource. */
157
+ sameNumberAs: number | null;
158
+ externalReference: string | null;
159
+ returnUrl: string | null;
160
+ errorCode: string | null;
161
+ /** Failed attempts of Facebook or Meta: at the fifth the link ends `failed`. */
162
+ failedAttempts: number;
163
+ expiresAt: Date;
164
+ createdAt: Date;
165
+ completedAt: Date | null;
166
+ }
167
+ /** An answer kept under an `Idempotency-Key` for 24 hours. */
168
+ interface IdempotentAnswer {
169
+ fingerprint: string;
170
+ status: number;
171
+ body: unknown;
172
+ headers: Record<string, string>;
173
+ storedAt: Date;
174
+ }
76
175
  interface Contact {
77
176
  id: number;
177
+ /** The workspace the contact is in; `null` counts as the default one. */
178
+ workspaceId: number | null;
78
179
  name: string | null;
79
180
  email: string | null;
80
181
  /** Digits only: the API stores the phone without `+`. */
@@ -136,9 +237,51 @@ interface CustomField {
136
237
  createdAt: Date;
137
238
  updatedAt: Date;
138
239
  }
240
+ /** A participant of a group: the phone in digits, and whether it is an admin. */
241
+ interface GroupParticipant {
242
+ phone: string;
243
+ name: string | null;
244
+ admin: boolean;
245
+ }
246
+ /** A WhatsApp group of a number of the account (communities `groups`). */
247
+ interface Group {
248
+ id: number;
249
+ /** The WhatsApp id of the group, `120363…@g.us`: the `{group}` of the routes and `group.uid` of the events. */
250
+ uid: string;
251
+ name: string;
252
+ description: string;
253
+ /** The number that is in the group (a QR number: the sandbox account has no official groups). */
254
+ deviceId: number;
255
+ /** The workspace the group is in; `null` counts as the default one. */
256
+ workspaceId: number | null;
257
+ participants: GroupParticipant[];
258
+ link: string;
259
+ createdAt: Date;
260
+ updatedAt: Date;
261
+ }
262
+ /** `queued` → `running` → `completed` | `failed` (communities `ApiGroupAction::publicStatus()`). */
263
+ type GroupActionStatus = 'queued' | 'running' | 'completed' | 'failed';
264
+ /** A group action by API (communities `api_group_actions`): here, only `send_message`. */
265
+ interface GroupAction {
266
+ uuid: string;
267
+ type: 'send_message';
268
+ status: GroupActionStatus;
269
+ deviceId: number;
270
+ groupId: number;
271
+ /** The workspace of the key that called (`call_context.workspace_id`). */
272
+ workspaceId: number;
273
+ result: Record<string, unknown> | null;
274
+ reason: string | null;
275
+ createdAt: Date;
276
+ startedAt: Date | null;
277
+ completedAt: Date | null;
278
+ failedAt: Date | null;
279
+ }
139
280
  type TemplateStatus = 'PENDING' | 'APPROVED' | 'REJECTED' | 'PAUSED' | 'DISABLED';
140
281
  interface Template {
141
282
  id: number;
283
+ /** The workspace it belongs to; `null` counts as the default one. */
284
+ workspaceId: number | null;
142
285
  uid: string;
143
286
  name: string;
144
287
  body: string;
@@ -164,6 +307,8 @@ interface Template {
164
307
  type SubscriptionStatus = 'active' | 'paused' | 'disabled';
165
308
  interface Subscription {
166
309
  id: string;
310
+ /** The workspace it belongs to: it only gets that workspace's events. `null` counts as the default one. */
311
+ workspaceId: number | null;
167
312
  url: string;
168
313
  description: string | null;
169
314
  events: string[];
@@ -251,6 +396,18 @@ interface RequestLogEntry {
251
396
  requestBody: unknown;
252
397
  responseBody: unknown;
253
398
  }
399
+ /** An event the sandbox emitted, delivered or not: the panel shows them, so a status is seen without a receiver. */
400
+ interface EmittedEvent {
401
+ envelope: {
402
+ id: string;
403
+ type: string;
404
+ version: number;
405
+ occurred_at: string;
406
+ data: unknown;
407
+ };
408
+ /** How many subscriptions got it. */
409
+ subscriptions: number;
410
+ }
254
411
  /** A failure armed with `POST /_sandbox/failures` or the `X-Sandbox-*` headers. */
255
412
  interface ArmedFailure {
256
413
  id: number;
@@ -274,6 +431,9 @@ declare class Sequence {
274
431
  }
275
432
  declare class Store {
276
433
  readonly historyLimit: number;
434
+ workspaces: Map<number, Workspace>;
435
+ /** The sandbox keys minted for a workspace (`POST /_sandbox/workspaces`, `/_sandbox/keys`): any other key is the default one's. */
436
+ keys: Map<string, number>;
277
437
  devices: Map<number, Device>;
278
438
  contacts: Map<number, Contact>;
279
439
  messages: Map<number, Message>;
@@ -283,10 +443,26 @@ declare class Store {
283
443
  subscriptions: Map<string, Subscription>;
284
444
  deliveries: Delivery[];
285
445
  requests: RequestLogEntry[];
446
+ events: EmittedEvent[];
286
447
  failures: ArmedFailure[];
287
448
  forms: Map<number, FormVersion>;
288
449
  formFamilies: Map<number, FormFamily>;
289
450
  formRuns: Map<number, FormRun>;
451
+ connectLinks: Map<number, ConnectLink>;
452
+ groups: Map<number, Group>;
453
+ groupActions: Map<string, GroupAction>;
454
+ /** When each `POST /connect-links` arrived in the last minute: the per-minute limit. */
455
+ linkAttempts: number[];
456
+ /** Answers by `Idempotency-Key`, per resource (`devices`, `connect-links`): one account. */
457
+ idempotency: Map<string, IdempotentAnswer>;
458
+ /** The number quota of the account and the switch of the Meta sign-up (`POST /_sandbox/numbers`). */
459
+ numbers: {
460
+ limit: number;
461
+ included: boolean;
462
+ trial: boolean;
463
+ metaConnect: boolean;
464
+ linksPerMinute: number;
465
+ };
290
466
  /** Last inbound message per `contactId:deviceId`: the 24-hour window. */
291
467
  lastInbound: Map<string, Date>;
292
468
  /** API-key sends per contact since its last inbound message: the antiblock counters. */
@@ -305,6 +481,8 @@ declare class Store {
305
481
  /** Salt of the deterministic event ids: new on every reset, so ids never repeat across sessions. */
306
482
  eventSalt: string;
307
483
  readonly ids: {
484
+ workspace: Sequence;
485
+ apiKey: Sequence;
308
486
  contact: Sequence;
309
487
  message: Sequence;
310
488
  tag: Sequence;
@@ -317,9 +495,15 @@ declare class Store {
317
495
  formFamily: Sequence;
318
496
  formVersion: Sequence;
319
497
  formRun: Sequence;
498
+ device: Sequence;
499
+ connectLink: Sequence;
500
+ group: Sequence;
320
501
  };
321
502
  constructor(historyLimit?: number);
503
+ /** The default workspace of the account: where what has no workspace belongs. */
504
+ get defaultWorkspace(): Workspace;
322
505
  logRequest(entry: Omit<RequestLogEntry, 'id'>): RequestLogEntry;
506
+ logEvent(entry: EmittedEvent): void;
323
507
  addDelivery(entry: Omit<Delivery, 'id'>): Delivery;
324
508
  findContactByPhone(phone: string): Contact | undefined;
325
509
  contactMessages(contactId: number): Message[];
@@ -339,12 +523,20 @@ declare class Store {
339
523
  * `429` is retried, any other answer that is not `2xx` is final;
340
524
  * - a delivery that runs out of attempts counts one consecutive failure; at 5 the subscription is disabled
341
525
  * (`too_many_failures`); a success resets the count;
342
- * - each attempt checks again that the subscription exists, is `active` and still wants the type.
526
+ * - each attempt checks again that the subscription exists, is `active` and still wants the type;
527
+ * - an event reaches only the subscriptions of its workspace, and `data.workspace_id` says which one (accounts
528
+ * v1.5.97 `EventWorkspaceRouting`, Q35 of 04-11): the workspace the emitter declares when it is one of the account,
529
+ * the default one otherwise. A subscription without a workspace counts as the default one's.
343
530
  */
344
531
 
345
532
  interface EmitOptions {
346
533
  id?: string;
347
534
  occurredAt?: Date;
535
+ /**
536
+ * The workspace the event belongs to: the number's for `device.*`, the contact's or the group's for the rest.
537
+ * Missing, `null` or not a workspace of the account: the default one.
538
+ */
539
+ workspaceId?: number | null;
348
540
  }
349
541
  interface Envelope$1 {
350
542
  id: string;
@@ -365,7 +557,10 @@ declare class Webhooks {
365
557
  get maxAttempts(): number;
366
558
  /** Builds the envelope, exactly as it is delivered. */
367
559
  envelope(type: string, data: unknown, options?: EmitOptions): Envelope$1;
368
- /** Emits one event to every active subscription that wants it. Returns the envelope and how many got it. */
560
+ /**
561
+ * Emits one event to every active subscription of its workspace that wants it. Returns the envelope and how many
562
+ * got it.
563
+ */
369
564
  emit(type: string, data: unknown, options?: EmitOptions): {
370
565
  envelope: Envelope$1;
371
566
  subscriptions: number;
@@ -374,7 +569,10 @@ declare class Webhooks {
374
569
  send(subscription: Subscription, type: string, body: string): Promise<SendResult>;
375
570
  private shouldRetry;
376
571
  private attempt;
377
- /** `POST /api/v1/webhooks/{id}/test`: one synchronous `webhook.test`, no retries, no counters touched. */
572
+ /**
573
+ * `POST /api/v1/webhooks/{id}/test`: one synchronous `webhook.test`, no retries, no counters touched. Its
574
+ * `data.workspace_id` is the subscription's workspace.
575
+ */
378
576
  test(subscription: Subscription): Promise<Record<string, unknown>>;
379
577
  }
380
578
 
@@ -398,7 +596,11 @@ declare class SandboxApp {
398
596
  readonly webhooks: Webhooks;
399
597
  /** Grows on every reset, so work started before a reset does not touch the new state. */
400
598
  generation: number;
599
+ /** The address the sandbox listens on, once it does: the host of the sign-up links when `publicUrl` is not set. */
600
+ listenUrl: string | null;
401
601
  constructor(config: SandboxConfig, logger?: Logger);
602
+ /** `http://host:port` of the sign-up page: `publicUrl`, or where the sandbox listens. */
603
+ get publicUrl(): string;
402
604
  private populate;
403
605
  /** `POST /_sandbox/reset`: empty state, the example data again, timers cancelled. */
404
606
  reset(): void;
@@ -487,4 +689,4 @@ declare const FORM_TEMPLATES: FormTemplate[];
487
689
 
488
690
  declare const VERSION: string;
489
691
 
490
- export { type CatalogEntry, type ConfigInput, type CreateSandboxOptions, DELIVERY_HEADER, EDGE_ERRORS, EVENT_HEADER, FAILURE_REASONS, FORM_TEMPLATES, META_ERRORS, type PresetSubscription, REJECTIONS, REQUEST_ID_HEADER, SEND_FILE_TYPES, SIGNATURE_HEADER, SUPPORTED_EXTENSIONS, type Sandbox, type SandboxConfig, VERSION, catalog, createSandbox, defaultConfig, mergeConfig, signature };
692
+ export { type CatalogEntry, type ConfigInput, type CreateSandboxOptions, DELIVERY_HEADER, EDGE_ERRORS, EVENT_HEADER, FAILURE_REASONS, FORM_TEMPLATES, META_ERRORS, type PresetSubscription, type PresetWorkspace, REJECTIONS, REQUEST_ID_HEADER, SEND_FILE_TYPES, SIGNATURE_HEADER, SUPPORTED_EXTENSIONS, type Sandbox, type SandboxConfig, VERSION, catalog, createSandbox, defaultConfig, mergeConfig, signature };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { DELIVERY_HEADER, EDGE_ERRORS, EVENT_HEADER, FAILURE_REASONS, FORM_TEMPLATES, META_ERRORS, REJECTIONS, REQUEST_ID_HEADER, SEND_FILE_TYPES, SIGNATURE_HEADER, SUPPORTED_EXTENSIONS, VERSION, catalog, createSandbox, defaultConfig, mergeConfig, signature } from './chunk-KH6A3I2A.js';
1
+ export { DELIVERY_HEADER, EDGE_ERRORS, EVENT_HEADER, FAILURE_REASONS, FORM_TEMPLATES, META_ERRORS, REJECTIONS, REQUEST_ID_HEADER, SEND_FILE_TYPES, SIGNATURE_HEADER, SUPPORTED_EXTENSIONS, VERSION, catalog, createSandbox, defaultConfig, mergeConfig, signature } from './chunk-PCGMUC35.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -4,6 +4,10 @@
4
4
  "webhooks": { "retryDelays": [5, 15, 30], "timeoutSeconds": 10 },
5
5
  "rules": { "window": true, "antiblock": true, "rateLimit": true },
6
6
  "templateApprovalSeconds": 5,
7
+ "numbers": { "limit": 5, "included": true, "trial": false, "metaConnect": false, "linksPerMinute": 10 },
8
+ "groupActions": true,
9
+ "publicUrl": null,
10
+ "workspaces": [{ "name": "Cliente B", "keys": ["2|fc_live_clienteB"] }],
7
11
  "subscriptions": [
8
12
  {
9
13
  "url": "http://localhost:3000/hooks/funnelchat",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelchat-hq/sandbox",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "A local server that imitates the Funnelchat public API and sends signed webhooks, with no real effects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -2,63 +2,67 @@
2
2
  "description": "Where each file of spec/ came from. Written by `npm run generate -- --spec <file>` or `-- --pending <file>`; do not edit it by hand. spec/pending-sandbox.json belongs to this repo: its sources are inside it.",
3
3
  "snapshot": {
4
4
  "file": "spec/funnelchat.json",
5
- "sha256": "8bbbae569b4cab520884db98f28204156c1bd6c629578bee609343c193e0dadb",
6
- "bytes": 635293,
5
+ "sha256": "0f451feaba59418f3a556f58856f841f12570973fd6525103e8cc0128ab64374",
6
+ "bytes": 1168453,
7
7
  "source": {
8
8
  "repository": "git@github.com:Funnelchat20/developers-portal.git",
9
- "path": "out/specs/funnelchat.json",
10
- "branch": "feat/openapi-unificada",
11
- "commit": "0ef4abb008870ed8c7cae49a08900a81e5e57ed8",
12
- "commit_date": "2026-10-15T10:53:11-03:00",
9
+ "path": "generated/specs/funnelchat-completa.json",
10
+ "branch": "main",
11
+ "commit": "c90565e4f1aa",
12
+ "commit_date": null,
13
13
  "file_tracked_in_git": false,
14
- "tracked_files_clean": true,
15
- "file_modified_at": "2026-10-15T14:11:20.569Z"
14
+ "tracked_files_clean": null,
15
+ "file_modified_at": "2026-11-04T21:06:16.945Z",
16
+ "note": "Built by `npm run build` of developers-portal at the merge of PR #33, deployed as v0.6.0 on 04-11. Not the published /specs/ file, which carries only the 23 visible operations."
16
17
  },
17
- "imported_at": "2026-10-16T11:46:40.094Z",
18
+ "imported_at": "2026-11-04T21:13:28.643Z",
18
19
  "spec": {
19
20
  "openapi": "3.1.0",
20
21
  "title": "Funnelchat API",
21
22
  "version": "v0",
22
- "paths": 191,
23
- "operations": 230,
24
- "webhooks": 28,
23
+ "paths": 203,
24
+ "operations": 248,
25
+ "webhooks": 29,
25
26
  "domains": [
26
27
  {
27
28
  "domain": "conversations",
28
- "sha": "9d723d52c",
29
- "branch": "snapshot/referencia-1310",
30
- "snapshot_at": "2026-10-13T10:41:30-03:00"
29
+ "tag": "v1.19.7",
30
+ "sha": "4e35ddb83",
31
+ "branch": null,
32
+ "snapshot_at": null
31
33
  },
32
34
  {
33
35
  "domain": "communities",
34
- "sha": "fab0bb10",
35
- "branch": "snapshot/referencia-1310",
36
- "snapshot_at": "2026-10-13T10:41:34-03:00"
36
+ "tag": "v2.35.5",
37
+ "sha": "2be913d4",
38
+ "branch": null,
39
+ "snapshot_at": null
37
40
  },
38
41
  {
39
42
  "domain": "accounts",
40
- "sha": "c234b6f8",
41
- "branch": "snapshot/referencia-1310",
42
- "snapshot_at": "2026-10-13T10:41:36-03:00"
43
+ "tag": "v1.5.97",
44
+ "sha": "558332bcf",
45
+ "branch": null,
46
+ "snapshot_at": null
43
47
  }
44
48
  ]
45
49
  }
46
50
  },
47
51
  "pending": {
48
52
  "file": "spec/pending.json",
49
- "sha256": "a14bc4dbc3025d3e958ffda8afd1fa9fdab34af264418060825f3300799aceb0",
50
- "bytes": 32775,
53
+ "sha256": "3ccf04ff5aa2b6acf6baa9b3d7e56ba1fee1e9c83ae1906b16cedb8422da942a",
54
+ "bytes": 116917,
51
55
  "source": {
52
56
  "repository": "git@github.com:Funnelchat20/funnelchat-node.git",
53
57
  "path": "spec/pending.json",
54
- "branch": "feat/inicial",
55
- "commit": "88557ce7819c5a4061e84c58053a1b6c49f35ec2",
56
- "commit_date": "2026-10-16T02:46:14-03:00",
58
+ "branch": "feat/primer-uso",
59
+ "commit": "8469a5c176ef36506b0102a68e2c506d0ff21407",
60
+ "commit_date": "2026-11-04T18:19:31-03:00",
57
61
  "file_tracked_in_git": true,
58
62
  "tracked_files_clean": true,
59
- "file_modified_at": "2026-10-16T05:29:09.348Z"
63
+ "file_modified_at": "2026-11-04T21:15:57.746Z"
60
64
  },
61
- "imported_at": "2026-10-16T11:46:40.294Z",
65
+ "imported_at": "2026-11-04T21:53:13.074Z",
62
66
  "note": "The pending layer of the Node SDK, unchanged. What belongs to the sandbox goes in spec/pending-sandbox.json."
63
67
  }
64
68
  }