@godxjp/server-sdk 0.2.0 → 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/README.md CHANGED
@@ -477,6 +477,11 @@ still actionable.
477
477
 
478
478
  ## `./producer` — the outbox producer kit
479
479
 
480
+ > **0.3.0 (breaking, nhỏ — server-sdk#4):** envelope của `drainOutbox` đổi
481
+ > `subject` từ NATS subject sang **`{aggregate}/{data.id}`** (join key, parity
482
+ > php-sdk); routing NATS vẫn là tham số `subject` NGOÀI envelope.
483
+ > `recordDomainEvent` nay BẮT BUỘC `data.id` (string khác rỗng).
484
+
480
485
  `./sync` is the CONSUMER half of the event discipline; this is the PRODUCER half (godx-jp/id#1963
481
486
  phase 4). A service that publishes its own domain events writes them to a D1 **outbox** row next
482
487
  to the state change they describe, and a relay drains the table in sequence order — so an event
@@ -50,7 +50,11 @@ interface DomainEnvelope {
50
50
  source: string;
51
51
  /** jp.godx.{service}.{aggregate}.{action} */
52
52
  type: string;
53
- /** godx.svc.{service}.{organizationId}.{aggregate}.{action} */
53
+ /**
54
+ * `{aggregate}/{data.id}` — join key cho consumer, KHÔNG phải subject NATS
55
+ * (routing đi bằng tham số `subject` của publish). Khớp php-sdk (godx-mailer#18,
56
+ * server-sdk#4); trước 0.3.0 field này nhầm là NATS subject.
57
+ */
54
58
  subject: string;
55
59
  time: string;
56
60
  datacontenttype: "application/json";
@@ -63,7 +67,10 @@ interface DomainEventInput {
63
67
  organizationId: string;
64
68
  aggregate: string;
65
69
  action: string;
66
- data: Record<string, unknown>;
70
+ /** PHẢI có `id` — join key của consumer (CE subject = `{aggregate}/{data.id}`, như php-sdk). */
71
+ data: Record<string, unknown> & {
72
+ id: string;
73
+ };
67
74
  /** CloudEvents id — generated (crypto.randomUUID) when not supplied. */
68
75
  id?: string;
69
76
  }
package/dist/producer.js CHANGED
@@ -30,6 +30,11 @@ async function recordDomainEvent(db, input) {
30
30
  const organizationId = requireToken("organizationId", input.organizationId);
31
31
  const aggregate = requireToken("aggregate", input.aggregate);
32
32
  const action = requireToken("action", input.action);
33
+ if (typeof input.data?.id !== "string" || input.data.id === "") {
34
+ throw new ProducerContractError(
35
+ "data.id (string, non-empty) is required \u2014 it is the consumer's join key and the CE subject's second half ({aggregate}/{data.id}), matching php-sdk."
36
+ );
37
+ }
33
38
  const subject = `godx.svc.${service}.${organizationId}.${aggregate}.${action}`;
34
39
  const type = `jp.godx.${service}.${aggregate}.${action}`;
35
40
  const id = input.id ?? crypto.randomUUID();
@@ -53,12 +58,15 @@ async function drainOutbox(db, publish, { batch = 100 } = {}) {
53
58
  // subject tokens are exactly `godx.svc.{service}` — the producer.
54
59
  source: row.subject.split(".").slice(0, 3).join("."),
55
60
  type: row.type,
56
- subject: row.subject,
61
+ // Token thứ 5 của subject NATS là aggregate (mỗi token đã cấm dấu chấm).
62
+ subject: "",
63
+ // điền dưới — cần data đã parse
57
64
  time: row.created_at,
58
65
  datacontenttype: "application/json",
59
66
  sequence: row.sequence,
60
67
  data: JSON.parse(row.data)
61
68
  };
69
+ envelope.subject = `${row.subject.split(".")[4]}/${String(envelope.data.id ?? "")}`;
62
70
  try {
63
71
  await publish({ subject: row.subject, envelope });
64
72
  } catch {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/producer.ts"],"sourcesContent":["/**\n * ./producer — the outbox half of the event discipline (godx-jp/id#1963,\n * phase 4): a service that PUBLISHES its own domain events writes them to a\n * D1 outbox row alongside its state change, and a relay drains the table in\n * sequence order. The envelope mirrors ./sync's CloudEvents 1.0 shape so\n * consumers reuse one parser; there is NO tenantid attribute — the tenant\n * rides in the subject, exactly like the identity feed.\n *\n * The transport is INJECTED (the `publish` callback) because a Cloudflare\n * Worker cannot dial NATS over TCP. Two deployment shapes, stated honestly:\n *\n * - **Workers-resident relay**: a Cron Trigger calling `drainOutbox`.\n * Cloudflare floors cron at 1 minute, so publish lag is ≥1 minute.\n * Do not promise consumers anything faster from this shape.\n * - **Host-side loop**: any long-lived process with a NATS client (nats.js on\n * Node, or the platform's own relay) polling `drainOutbox` gets sub-second\n * lag. Same function, different clock.\n */\n\n/** Structural subset of D1Database, so this module has no CF type dependency. */\ninterface D1Like {\n prepare(sql: string): {\n bind(...values: unknown[]): {\n first<T = unknown>(): Promise<T | null>;\n run(): Promise<unknown>;\n all<T = unknown>(): Promise<{ results: T[] }>;\n };\n };\n}\n\nexport class ProducerContractError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ProducerContractError\";\n }\n}\n\n/**\n * DDL for the outbox table — copy into a migration verbatim (drizzle users:\n * keep the ORM schema in lockstep). The index serves `drainOutbox`'s\n * \"unpublished, in sequence order\" read.\n */\nexport const OUTBOX_TABLE_SQL = `CREATE TABLE IF NOT EXISTS outbox (\n id TEXT PRIMARY KEY,\n sequence INTEGER NOT NULL,\n subject TEXT NOT NULL,\n type TEXT NOT NULL,\n organization_id TEXT NOT NULL,\n data TEXT NOT NULL,\n created_at TEXT NOT NULL,\n published_at TEXT NULL\n);\nCREATE INDEX IF NOT EXISTS outbox_unpublished_idx ON outbox (published_at, sequence);`;\n\n/**\n * CloudEvents 1.0 envelope as `drainOutbox` hands it to `publish` — the same\n * shape ./sync's IdentityEnvelope reads, and deliberately WITHOUT a tenantid\n * attribute: the tenant is the subject's `{organizationId}` token.\n */\nexport interface DomainEnvelope {\n specversion: \"1.0\";\n /** UUIDv4 — THE idempotency key for consumers. */\n id: string;\n /** Producer identity: `godx.svc.{service}` (the subject's first three tokens). */\n source: string;\n /** jp.godx.{service}.{aggregate}.{action} */\n type: string;\n /** godx.svc.{service}.{organizationId}.{aggregate}.{action} */\n subject: string;\n time: string;\n datacontenttype: \"application/json\";\n /** Per-producer monotonic ordering fence (outbox.sequence). */\n sequence: number;\n data: Record<string, unknown>;\n}\n\nexport interface DomainEventInput {\n service: string;\n organizationId: string;\n aggregate: string;\n action: string;\n data: Record<string, unknown>;\n /** CloudEvents id — generated (crypto.randomUUID) when not supplied. */\n id?: string;\n}\n\nexport interface RecordedDomainEvent {\n id: string;\n sequence: number;\n subject: string;\n type: string;\n}\n\n/** Every subject/type token: letters, digits, `_`, `-` — never `.`, which separates tokens. */\nconst TOKEN = /^[A-Za-z0-9_-]+$/;\n\nfunction requireToken(name: string, value: string): string {\n if (!TOKEN.test(value)) {\n throw new ProducerContractError(\n `${name} ${JSON.stringify(value)} is not a valid subject token — expected /^[A-Za-z0-9_-]+$/ (\".\" separates tokens and may not appear inside one).`,\n );\n }\n return value;\n}\n\n/**\n * Record one domain event in the outbox, next to the state change it\n * describes. Composes:\n * - subject = `godx.svc.{service}.{organizationId}.{aggregate}.{action}`\n * - type = `jp.godx.{service}.{aggregate}.{action}`\n *\n * Sequence is per-producer monotonic via `MAX(sequence) + 1`. That\n * read-then-insert is racy on paper; on D1 it is safe in practice because\n * D1 serializes writes per database — two invocations cannot interleave\n * between the SELECT and the INSERT. On any other SQLite with genuinely\n * concurrent writers, run this inside the caller's transaction (which is\n * where it belongs anyway: the event must not outlive a rolled-back write).\n */\nexport async function recordDomainEvent(db: D1Like, input: DomainEventInput): Promise<RecordedDomainEvent> {\n const service = requireToken(\"service\", input.service);\n const organizationId = requireToken(\"organizationId\", input.organizationId);\n const aggregate = requireToken(\"aggregate\", input.aggregate);\n const action = requireToken(\"action\", input.action);\n\n const subject = `godx.svc.${service}.${organizationId}.${aggregate}.${action}`;\n const type = `jp.godx.${service}.${aggregate}.${action}`;\n const id = input.id ?? crypto.randomUUID();\n\n const next = await db\n .prepare(\"SELECT COALESCE(MAX(sequence), 0) + 1 AS next FROM outbox\")\n .bind()\n .first<{ next: number }>();\n const sequence = Number(next?.next ?? 1);\n\n await db\n .prepare(\n \"INSERT INTO outbox (id, sequence, subject, type, organization_id, data, created_at, published_at) VALUES (?, ?, ?, ?, ?, ?, ?, NULL)\",\n )\n .bind(id, sequence, subject, type, organizationId, JSON.stringify(input.data), new Date().toISOString())\n .run();\n\n return { id, sequence, subject, type };\n}\n\n/**\n * Publish unpublished rows in sequence order through the injected transport.\n * `published_at` is marked only AFTER `publish` resolves — a crash between\n * the two re-publishes the row, so consumers dedupe on the CloudEvents `id`\n * (at-least-once, exactly like the identity feed). The drain STOPS at the\n * first failure so no later event overtakes an earlier one; the failed row\n * stays unpublished and the next drain retries it, so inspect `remaining`\n * rather than expecting a throw.\n */\nexport async function drainOutbox(\n db: D1Like,\n publish: (event: { subject: string; envelope: DomainEnvelope }) => Promise<void>,\n { batch = 100 }: { batch?: number } = {},\n): Promise<{ published: number; remaining: number }> {\n interface Row {\n id: string;\n sequence: number;\n subject: string;\n type: string;\n data: string;\n created_at: string;\n }\n const { results } = await db\n .prepare(\n \"SELECT id, sequence, subject, type, data, created_at FROM outbox WHERE published_at IS NULL ORDER BY sequence LIMIT ?\",\n )\n .bind(batch)\n .all<Row>();\n\n let published = 0;\n for (const row of results) {\n const envelope: DomainEnvelope = {\n specversion: \"1.0\",\n id: row.id,\n // Tokens cannot contain \".\" (validated on record), so the first three\n // subject tokens are exactly `godx.svc.{service}` — the producer.\n source: row.subject.split(\".\").slice(0, 3).join(\".\"),\n type: row.type,\n subject: row.subject,\n time: row.created_at,\n datacontenttype: \"application/json\",\n sequence: row.sequence,\n data: JSON.parse(row.data) as Record<string, unknown>,\n };\n try {\n await publish({ subject: row.subject, envelope });\n } catch {\n break; // order preserved: nothing after the failed row may go out first\n }\n await db.prepare(\"UPDATE outbox SET published_at = ? WHERE id = ?\").bind(new Date().toISOString(), row.id).run();\n published++;\n }\n\n const count = await db\n .prepare(\"SELECT COUNT(*) AS n FROM outbox WHERE published_at IS NULL\")\n .bind()\n .first<{ n: number }>();\n return { published, remaining: Number(count?.n ?? 0) };\n}\n"],"mappings":";AA8BO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAOO,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoDhC,IAAM,QAAQ;AAEd,SAAS,aAAa,MAAc,OAAuB;AACzD,MAAI,CAAC,MAAM,KAAK,KAAK,GAAG;AACtB,UAAM,IAAI;AAAA,MACR,GAAG,IAAI,IAAI,KAAK,UAAU,KAAK,CAAC;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAeA,eAAsB,kBAAkB,IAAY,OAAuD;AACzG,QAAM,UAAU,aAAa,WAAW,MAAM,OAAO;AACrD,QAAM,iBAAiB,aAAa,kBAAkB,MAAM,cAAc;AAC1E,QAAM,YAAY,aAAa,aAAa,MAAM,SAAS;AAC3D,QAAM,SAAS,aAAa,UAAU,MAAM,MAAM;AAElD,QAAM,UAAU,YAAY,OAAO,IAAI,cAAc,IAAI,SAAS,IAAI,MAAM;AAC5E,QAAM,OAAO,WAAW,OAAO,IAAI,SAAS,IAAI,MAAM;AACtD,QAAM,KAAK,MAAM,MAAM,OAAO,WAAW;AAEzC,QAAM,OAAO,MAAM,GAChB,QAAQ,2DAA2D,EACnE,KAAK,EACL,MAAwB;AAC3B,QAAM,WAAW,OAAO,MAAM,QAAQ,CAAC;AAEvC,QAAM,GACH;AAAA,IACC;AAAA,EACF,EACC,KAAK,IAAI,UAAU,SAAS,MAAM,gBAAgB,KAAK,UAAU,MAAM,IAAI,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,EACtG,IAAI;AAEP,SAAO,EAAE,IAAI,UAAU,SAAS,KAAK;AACvC;AAWA,eAAsB,YACpB,IACA,SACA,EAAE,QAAQ,IAAI,IAAwB,CAAC,GACY;AASnD,QAAM,EAAE,QAAQ,IAAI,MAAM,GACvB;AAAA,IACC;AAAA,EACF,EACC,KAAK,KAAK,EACV,IAAS;AAEZ,MAAI,YAAY;AAChB,aAAW,OAAO,SAAS;AACzB,UAAM,WAA2B;AAAA,MAC/B,aAAa;AAAA,MACb,IAAI,IAAI;AAAA;AAAA;AAAA,MAGR,QAAQ,IAAI,QAAQ,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AAAA,MACnD,MAAM,IAAI;AAAA,MACV,SAAS,IAAI;AAAA,MACb,MAAM,IAAI;AAAA,MACV,iBAAiB;AAAA,MACjB,UAAU,IAAI;AAAA,MACd,MAAM,KAAK,MAAM,IAAI,IAAI;AAAA,IAC3B;AACA,QAAI;AACF,YAAM,QAAQ,EAAE,SAAS,IAAI,SAAS,SAAS,CAAC;AAAA,IAClD,QAAQ;AACN;AAAA,IACF;AACA,UAAM,GAAG,QAAQ,iDAAiD,EAAE,MAAK,oBAAI,KAAK,GAAE,YAAY,GAAG,IAAI,EAAE,EAAE,IAAI;AAC/G;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,GACjB,QAAQ,6DAA6D,EACrE,KAAK,EACL,MAAqB;AACxB,SAAO,EAAE,WAAW,WAAW,OAAO,OAAO,KAAK,CAAC,EAAE;AACvD;","names":[]}
1
+ {"version":3,"sources":["../src/producer.ts"],"sourcesContent":["/**\n * ./producer — the outbox half of the event discipline (godx-jp/id#1963,\n * phase 4): a service that PUBLISHES its own domain events writes them to a\n * D1 outbox row alongside its state change, and a relay drains the table in\n * sequence order. The envelope mirrors ./sync's CloudEvents 1.0 shape so\n * consumers reuse one parser; there is NO tenantid attribute — the tenant\n * rides in the subject, exactly like the identity feed.\n *\n * The transport is INJECTED (the `publish` callback) because a Cloudflare\n * Worker cannot dial NATS over TCP. Two deployment shapes, stated honestly:\n *\n * - **Workers-resident relay**: a Cron Trigger calling `drainOutbox`.\n * Cloudflare floors cron at 1 minute, so publish lag is ≥1 minute.\n * Do not promise consumers anything faster from this shape.\n * - **Host-side loop**: any long-lived process with a NATS client (nats.js on\n * Node, or the platform's own relay) polling `drainOutbox` gets sub-second\n * lag. Same function, different clock.\n */\n\n/** Structural subset of D1Database, so this module has no CF type dependency. */\ninterface D1Like {\n prepare(sql: string): {\n bind(...values: unknown[]): {\n first<T = unknown>(): Promise<T | null>;\n run(): Promise<unknown>;\n all<T = unknown>(): Promise<{ results: T[] }>;\n };\n };\n}\n\nexport class ProducerContractError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ProducerContractError\";\n }\n}\n\n/**\n * DDL for the outbox table — copy into a migration verbatim (drizzle users:\n * keep the ORM schema in lockstep). The index serves `drainOutbox`'s\n * \"unpublished, in sequence order\" read.\n */\nexport const OUTBOX_TABLE_SQL = `CREATE TABLE IF NOT EXISTS outbox (\n id TEXT PRIMARY KEY,\n sequence INTEGER NOT NULL,\n subject TEXT NOT NULL,\n type TEXT NOT NULL,\n organization_id TEXT NOT NULL,\n data TEXT NOT NULL,\n created_at TEXT NOT NULL,\n published_at TEXT NULL\n);\nCREATE INDEX IF NOT EXISTS outbox_unpublished_idx ON outbox (published_at, sequence);`;\n\n/**\n * CloudEvents 1.0 envelope as `drainOutbox` hands it to `publish` — the same\n * shape ./sync's IdentityEnvelope reads, and deliberately WITHOUT a tenantid\n * attribute: the tenant is the subject's `{organizationId}` token.\n */\nexport interface DomainEnvelope {\n specversion: \"1.0\";\n /** UUIDv4 — THE idempotency key for consumers. */\n id: string;\n /** Producer identity: `godx.svc.{service}` (the subject's first three tokens). */\n source: string;\n /** jp.godx.{service}.{aggregate}.{action} */\n type: string;\n /**\n * `{aggregate}/{data.id}` — join key cho consumer, KHÔNG phải subject NATS\n * (routing đi bằng tham số `subject` của publish). Khớp php-sdk (godx-mailer#18,\n * server-sdk#4); trước 0.3.0 field này nhầm là NATS subject.\n */\n subject: string;\n time: string;\n datacontenttype: \"application/json\";\n /** Per-producer monotonic ordering fence (outbox.sequence). */\n sequence: number;\n data: Record<string, unknown>;\n}\n\nexport interface DomainEventInput {\n service: string;\n organizationId: string;\n aggregate: string;\n action: string;\n /** PHẢI có `id` — join key của consumer (CE subject = `{aggregate}/{data.id}`, như php-sdk). */\n data: Record<string, unknown> & { id: string };\n /** CloudEvents id — generated (crypto.randomUUID) when not supplied. */\n id?: string;\n}\n\nexport interface RecordedDomainEvent {\n id: string;\n sequence: number;\n subject: string;\n type: string;\n}\n\n/** Every subject/type token: letters, digits, `_`, `-` — never `.`, which separates tokens. */\nconst TOKEN = /^[A-Za-z0-9_-]+$/;\n\nfunction requireToken(name: string, value: string): string {\n if (!TOKEN.test(value)) {\n throw new ProducerContractError(\n `${name} ${JSON.stringify(value)} is not a valid subject token — expected /^[A-Za-z0-9_-]+$/ (\".\" separates tokens and may not appear inside one).`,\n );\n }\n return value;\n}\n\n/**\n * Record one domain event in the outbox, next to the state change it\n * describes. Composes:\n * - subject = `godx.svc.{service}.{organizationId}.{aggregate}.{action}`\n * - type = `jp.godx.{service}.{aggregate}.{action}`\n *\n * Sequence is per-producer monotonic via `MAX(sequence) + 1`. That\n * read-then-insert is racy on paper; on D1 it is safe in practice because\n * D1 serializes writes per database — two invocations cannot interleave\n * between the SELECT and the INSERT. On any other SQLite with genuinely\n * concurrent writers, run this inside the caller's transaction (which is\n * where it belongs anyway: the event must not outlive a rolled-back write).\n */\nexport async function recordDomainEvent(db: D1Like, input: DomainEventInput): Promise<RecordedDomainEvent> {\n const service = requireToken(\"service\", input.service);\n const organizationId = requireToken(\"organizationId\", input.organizationId);\n const aggregate = requireToken(\"aggregate\", input.aggregate);\n const action = requireToken(\"action\", input.action);\n if (typeof input.data?.id !== \"string\" || input.data.id === \"\") {\n throw new ProducerContractError(\n \"data.id (string, non-empty) is required — it is the consumer's join key and the CE subject's second half ({aggregate}/{data.id}), matching php-sdk.\",\n );\n }\n\n const subject = `godx.svc.${service}.${organizationId}.${aggregate}.${action}`;\n const type = `jp.godx.${service}.${aggregate}.${action}`;\n const id = input.id ?? crypto.randomUUID();\n\n const next = await db\n .prepare(\"SELECT COALESCE(MAX(sequence), 0) + 1 AS next FROM outbox\")\n .bind()\n .first<{ next: number }>();\n const sequence = Number(next?.next ?? 1);\n\n await db\n .prepare(\n \"INSERT INTO outbox (id, sequence, subject, type, organization_id, data, created_at, published_at) VALUES (?, ?, ?, ?, ?, ?, ?, NULL)\",\n )\n .bind(id, sequence, subject, type, organizationId, JSON.stringify(input.data), new Date().toISOString())\n .run();\n\n return { id, sequence, subject, type };\n}\n\n/**\n * Publish unpublished rows in sequence order through the injected transport.\n * `published_at` is marked only AFTER `publish` resolves — a crash between\n * the two re-publishes the row, so consumers dedupe on the CloudEvents `id`\n * (at-least-once, exactly like the identity feed). The drain STOPS at the\n * first failure so no later event overtakes an earlier one; the failed row\n * stays unpublished and the next drain retries it, so inspect `remaining`\n * rather than expecting a throw.\n */\nexport async function drainOutbox(\n db: D1Like,\n publish: (event: { subject: string; envelope: DomainEnvelope }) => Promise<void>,\n { batch = 100 }: { batch?: number } = {},\n): Promise<{ published: number; remaining: number }> {\n interface Row {\n id: string;\n sequence: number;\n subject: string;\n type: string;\n data: string;\n created_at: string;\n }\n const { results } = await db\n .prepare(\n \"SELECT id, sequence, subject, type, data, created_at FROM outbox WHERE published_at IS NULL ORDER BY sequence LIMIT ?\",\n )\n .bind(batch)\n .all<Row>();\n\n let published = 0;\n for (const row of results) {\n const envelope: DomainEnvelope = {\n specversion: \"1.0\",\n id: row.id,\n // Tokens cannot contain \".\" (validated on record), so the first three\n // subject tokens are exactly `godx.svc.{service}` — the producer.\n source: row.subject.split(\".\").slice(0, 3).join(\".\"),\n type: row.type,\n // Token thứ 5 của subject NATS là aggregate (mỗi token đã cấm dấu chấm).\n subject: \"\", // điền dưới — cần data đã parse\n time: row.created_at,\n datacontenttype: \"application/json\",\n sequence: row.sequence,\n data: JSON.parse(row.data) as Record<string, unknown>,\n };\n envelope.subject = `${row.subject.split(\".\")[4]}/${String(envelope.data.id ?? \"\")}`;\n try {\n await publish({ subject: row.subject, envelope });\n } catch {\n break; // order preserved: nothing after the failed row may go out first\n }\n await db.prepare(\"UPDATE outbox SET published_at = ? WHERE id = ?\").bind(new Date().toISOString(), row.id).run();\n published++;\n }\n\n const count = await db\n .prepare(\"SELECT COUNT(*) AS n FROM outbox WHERE published_at IS NULL\")\n .bind()\n .first<{ n: number }>();\n return { published, remaining: Number(count?.n ?? 0) };\n}\n"],"mappings":";AA8BO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAOO,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDhC,IAAM,QAAQ;AAEd,SAAS,aAAa,MAAc,OAAuB;AACzD,MAAI,CAAC,MAAM,KAAK,KAAK,GAAG;AACtB,UAAM,IAAI;AAAA,MACR,GAAG,IAAI,IAAI,KAAK,UAAU,KAAK,CAAC;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAeA,eAAsB,kBAAkB,IAAY,OAAuD;AACzG,QAAM,UAAU,aAAa,WAAW,MAAM,OAAO;AACrD,QAAM,iBAAiB,aAAa,kBAAkB,MAAM,cAAc;AAC1E,QAAM,YAAY,aAAa,aAAa,MAAM,SAAS;AAC3D,QAAM,SAAS,aAAa,UAAU,MAAM,MAAM;AAClD,MAAI,OAAO,MAAM,MAAM,OAAO,YAAY,MAAM,KAAK,OAAO,IAAI;AAC9D,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,YAAY,OAAO,IAAI,cAAc,IAAI,SAAS,IAAI,MAAM;AAC5E,QAAM,OAAO,WAAW,OAAO,IAAI,SAAS,IAAI,MAAM;AACtD,QAAM,KAAK,MAAM,MAAM,OAAO,WAAW;AAEzC,QAAM,OAAO,MAAM,GAChB,QAAQ,2DAA2D,EACnE,KAAK,EACL,MAAwB;AAC3B,QAAM,WAAW,OAAO,MAAM,QAAQ,CAAC;AAEvC,QAAM,GACH;AAAA,IACC;AAAA,EACF,EACC,KAAK,IAAI,UAAU,SAAS,MAAM,gBAAgB,KAAK,UAAU,MAAM,IAAI,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,EACtG,IAAI;AAEP,SAAO,EAAE,IAAI,UAAU,SAAS,KAAK;AACvC;AAWA,eAAsB,YACpB,IACA,SACA,EAAE,QAAQ,IAAI,IAAwB,CAAC,GACY;AASnD,QAAM,EAAE,QAAQ,IAAI,MAAM,GACvB;AAAA,IACC;AAAA,EACF,EACC,KAAK,KAAK,EACV,IAAS;AAEZ,MAAI,YAAY;AAChB,aAAW,OAAO,SAAS;AACzB,UAAM,WAA2B;AAAA,MAC/B,aAAa;AAAA,MACb,IAAI,IAAI;AAAA;AAAA;AAAA,MAGR,QAAQ,IAAI,QAAQ,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AAAA,MACnD,MAAM,IAAI;AAAA;AAAA,MAEV,SAAS;AAAA;AAAA,MACT,MAAM,IAAI;AAAA,MACV,iBAAiB;AAAA,MACjB,UAAU,IAAI;AAAA,MACd,MAAM,KAAK,MAAM,IAAI,IAAI;AAAA,IAC3B;AACA,aAAS,UAAU,GAAG,IAAI,QAAQ,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI,OAAO,SAAS,KAAK,MAAM,EAAE,CAAC;AACjF,QAAI;AACF,YAAM,QAAQ,EAAE,SAAS,IAAI,SAAS,SAAS,CAAC;AAAA,IAClD,QAAQ;AACN;AAAA,IACF;AACA,UAAM,GAAG,QAAQ,iDAAiD,EAAE,MAAK,oBAAI,KAAK,GAAE,YAAY,GAAG,IAAI,EAAE,EAAE,IAAI;AAC/G;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,GACjB,QAAQ,6DAA6D,EACrE,KAAK,EACL,MAAqB;AACxB,SAAO,EAAE,WAAW,WAAW,OAAO,OAAO,KAAK,CAAC,EAAE;AACvD;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@godxjp/server-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "GoDX server-side SDK (Workers/Node) — holds service credentials; for browser code use @godxjp/web-sdk. Counterpart of godx-jp/php-sdk.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -93,4 +93,4 @@
93
93
  "publishConfig": {
94
94
  "access": "public"
95
95
  }
96
- }
96
+ }