@automagik/omni 2.261006.2 → 2.261008.2

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/index.js CHANGED
@@ -137462,7 +137462,7 @@ import { fileURLToPath } from "url";
137462
137462
  // package.json
137463
137463
  var package_default = {
137464
137464
  name: "@automagik/omni",
137465
- version: "2.261006.2",
137465
+ version: "2.261008.2",
137466
137466
  repository: {
137467
137467
  type: "git",
137468
137468
  url: "git+https://github.com/automagik-dev/omni.git",
@@ -266444,7 +266444,7 @@ var init_sentry_scrub = __esm(() => {
266444
266444
  var require_package7 = __commonJS((exports, module) => {
266445
266445
  module.exports = {
266446
266446
  name: "@omni/api",
266447
- version: "2.261006.2",
266447
+ version: "2.261008.2",
266448
266448
  private: true,
266449
266449
  type: "module",
266450
266450
  exports: {
@@ -266504,6 +266504,7 @@ var require_package7 = __commonJS((exports, module) => {
266504
266504
  "@asteasolutions/zod-to-openapi": "7.3.4",
266505
266505
  "@types/qrcode-terminal": "^0.12.2",
266506
266506
  "@types/bun": "1.3.14",
266507
+ baileys: "file:../channel-whatsapp/vendor/baileys-v7.0.0-rc14.tgz",
266507
266508
  "openapi3-ts": "^4.5.0",
266508
266509
  "qrcode-terminal": "^0.12.0",
266509
266510
  typescript: "^5.7.3"
@@ -327263,7 +327264,7 @@ var init_worker_tenant_context = __esm(() => {
327263
327264
  });
327264
327265
 
327265
327266
  // ../api/src/middleware/config-audit.ts
327266
- import { createHash as createHash12 } from "crypto";
327267
+ import { createHash as createHash13 } from "crypto";
327267
327268
  function resolveTarget(method, path2) {
327268
327269
  const rel = path2.replace(/^\/api\/v2/, "").replace(/\/$/, "");
327269
327270
  for (const resource of RESOURCES) {
@@ -327277,7 +327278,7 @@ function resolveTarget(method, path2) {
327277
327278
  return null;
327278
327279
  }
327279
327280
  function fingerprint(value) {
327280
- return `sha256:${createHash12("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 12)}`;
327281
+ return `sha256:${createHash13("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 12)}`;
327281
327282
  }
327282
327283
  function redactSecrets2(value, keyName = "") {
327283
327284
  if (value === null || value === undefined)
@@ -327612,9 +327613,9 @@ var init_body_limit2 = __esm(() => {
327612
327613
  });
327613
327614
 
327614
327615
  // ../api/src/middleware/genie-signature.ts
327615
- import { createHash as createHash13, createPublicKey, verify } from "crypto";
327616
+ import { createHash as createHash14, createPublicKey, verify } from "crypto";
327616
327617
  function canonicalSigningInput(timestamp3, method, path2, body) {
327617
- const bodyHash = createHash13("sha256").update(body, "utf-8").digest("hex");
327618
+ const bodyHash = createHash14("sha256").update(body, "utf-8").digest("hex");
327618
327619
  return `${timestamp3}
327619
327620
  ${method.toUpperCase()}
327620
327621
  ${path2}
@@ -327882,12 +327883,12 @@ var init_profiles = __esm(() => {
327882
327883
  });
327883
327884
 
327884
327885
  // ../api/src/middleware/output-redactor.ts
327885
- import { createHash as createHash14 } from "crypto";
327886
+ import { createHash as createHash15 } from "crypto";
327886
327887
  function escapeRegex(literal2) {
327887
327888
  return literal2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
327888
327889
  }
327889
327890
  function hashPattern(source) {
327890
- return createHash14("sha256").update(source).digest("hex").slice(0, 12);
327891
+ return createHash15("sha256").update(source).digest("hex").slice(0, 12);
327891
327892
  }
327892
327893
  function compilePatterns(literals) {
327893
327894
  const out = [];
@@ -328137,6 +328138,12 @@ var DEFAULT_TURN_SCOPES, SCOPE_MAP;
328137
328138
  var init_scopes = __esm(() => {
328138
328139
  DEFAULT_TURN_SCOPES = ["messages:send", "turns:close", "tts:synthesize", "context:read"];
328139
328140
  SCOPE_MAP = {
328141
+ "GET /instances/:id/self": "instances:read",
328142
+ "GET /instances/:id/self/chats": "messages:selected:read",
328143
+ "POST /instances/:id/self/messages": "messages:self:read",
328144
+ "POST /instances/:id/self/receipt": "messages:self:read",
328145
+ "POST /instances/:id/self/history": "messages:selected:read",
328146
+ "POST /messages/send-self": "messages:self:send",
328140
328147
  "GET /audit": "audit:read",
328141
328148
  "GET /audit/:id": "audit:read",
328142
328149
  "GET /a2a/agents": "agents:read",
@@ -329153,6 +329160,8 @@ var init_route_ownership = __esm(() => {
329153
329160
  "GET /api/v2/instances/:id/passkey",
329154
329161
  "GET /api/v2/instances/:id/privacy",
329155
329162
  "GET /api/v2/instances/:id/qr",
329163
+ "GET /api/v2/instances/:id/self",
329164
+ "GET /api/v2/instances/:id/self/chats",
329156
329165
  "GET /api/v2/instances/:id/status",
329157
329166
  "GET /api/v2/instances/:id/sync",
329158
329167
  "GET /api/v2/instances/:id/sync/:jobId",
@@ -329236,6 +329245,10 @@ var init_route_ownership = __esm(() => {
329236
329245
  "POST /api/v2/:id/test",
329237
329246
  "POST /api/v2/access/check",
329238
329247
  "POST /api/v2/access/rules",
329248
+ "POST /api/v2/instances/:id/self/history",
329249
+ "POST /api/v2/instances/:id/self/messages",
329250
+ "POST /api/v2/instances/:id/self/receipt",
329251
+ "POST /api/v2/messages/send-self",
329239
329252
  "POST /api/v2/agent-tasks",
329240
329253
  "POST /api/v2/agents",
329241
329254
  "POST /api/v2/agents/:id/identities/link",
@@ -329462,6 +329475,10 @@ var init_route_ownership = __esm(() => {
329462
329475
 
329463
329476
  // ../api/src/tenancy/scope-projection.ts
329464
329477
  function classifyLegacyScope(scope) {
329478
+ if (scope === "messages:self:read" || scope === "messages:selected:read")
329479
+ return "read";
329480
+ if (scope === "messages:self:send")
329481
+ return "write";
329465
329482
  const verb = scope.split(":")[1];
329466
329483
  if (verb === undefined)
329467
329484
  return null;
@@ -330701,7 +330718,7 @@ var require_gaxios = __commonJS((exports) => {
330701
330718
  var retry_js_1 = require_retry2();
330702
330719
  var stream_1 = __require("stream");
330703
330720
  var interceptor_js_1 = require_interceptor();
330704
- var randomUUID2 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
330721
+ var randomUUID3 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
330705
330722
  var HTTP_STATUS_NO_CONTENT = 204;
330706
330723
 
330707
330724
  class Gaxios {
@@ -330912,7 +330929,7 @@ var require_gaxios = __commonJS((exports) => {
330912
330929
  }
330913
330930
  const shouldDirectlyPassData = typeof opts.data === "string" || opts.data instanceof ArrayBuffer || opts.data instanceof Blob || globalThis.File && opts.data instanceof File || opts.data instanceof FormData || opts.data instanceof stream_1.Readable || opts.data instanceof ReadableStream || opts.data instanceof String || opts.data instanceof URLSearchParams || ArrayBuffer.isView(opts.data) || ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
330914
330931
  if (opts.multipart?.length) {
330915
- const boundary = await randomUUID2();
330932
+ const boundary = await randomUUID3();
330916
330933
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
330917
330934
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
330918
330935
  } else if (shouldDirectlyPassData) {
@@ -378596,7 +378613,7 @@ var init_storage = __esm(() => {
378596
378613
  });
378597
378614
 
378598
378615
  // ../api/src/plugins/context.ts
378599
- import { randomUUID as randomUUID2 } from "crypto";
378616
+ import { randomUUID as randomUUID3 } from "crypto";
378600
378617
  function createPluginDatabase(db2) {
378601
378618
  return {
378602
378619
  async execute(_sql, _params) {
@@ -378611,7 +378628,7 @@ function createPluginDatabase(db2) {
378611
378628
  function createIngressClaim(db2) {
378612
378629
  return {
378613
378630
  async claim({ idempotencyKey, instanceId, channelType, externalId, eventType = "message.received" }) {
378614
- const id = randomUUID2();
378631
+ const id = randomUUID3();
378615
378632
  try {
378616
378633
  const claimed = await db2.insert(omniEvents).values({
378617
378634
  id,
@@ -379855,12 +379872,12 @@ var init_message_persistence = __esm(() => {
379855
379872
  });
379856
379873
 
379857
379874
  // ../api/src/plugins/agent-dispatcher.ts
379858
- import { createHash as createHash15 } from "crypto";
379875
+ import { createHash as createHash16 } from "crypto";
379859
379876
  import { unlink, writeFile as writeFile4 } from "fs/promises";
379860
379877
  import { tmpdir as tmpdir11 } from "os";
379861
379878
  import { join as join22, resolve as resolve3 } from "path";
379862
379879
  function sha256Digest(value) {
379863
- return `sha256:${createHash15("sha256").update(value).digest("hex")}`;
379880
+ return `sha256:${createHash16("sha256").update(value).digest("hex")}`;
379864
379881
  }
379865
379882
  function redactLifecycleText(value) {
379866
379883
  return value.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, "[EMAIL]").replace(/\b\+?\d[\d\s().-]{5,}\d\b/g, "[PHONE]").replace(/\b\d{6,}\b/g, "[NUMBER]").replace(/\b[^\s@]+@(s\.whatsapp\.net|g\.us|lid|newsletter)\b/gi, "[JID]");
@@ -384102,7 +384119,7 @@ var init_batch_pricing = __esm(() => {
384102
384119
  });
384103
384120
 
384104
384121
  // ../api/src/services/media-storage.ts
384105
- import { randomUUID as randomUUID3 } from "crypto";
384122
+ import { randomUUID as randomUUID4 } from "crypto";
384106
384123
  import { existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
384107
384124
  import { rm as rm3, writeFile as writeFile5 } from "fs/promises";
384108
384125
  import { tmpdir as tmpdir12 } from "os";
@@ -384336,7 +384353,7 @@ class MediaStorageService {
384336
384353
  }
384337
384354
  const buffer3 = await this.backend.read(reference);
384338
384355
  const ext = extname2(reference) || ".bin";
384339
- const tempPath = join23(tmpdir12(), `omni-media-${randomUUID3()}${ext}`);
384356
+ const tempPath = join23(tmpdir12(), `omni-media-${randomUUID4()}${ext}`);
384340
384357
  try {
384341
384358
  await writeFile5(tempPath, buffer3);
384342
384359
  } catch (error3) {
@@ -386223,7 +386240,7 @@ var init_events2 = __esm(() => {
386223
386240
  });
386224
386241
 
386225
386242
  // ../api/src/services/event-consumers.ts
386226
- import { randomUUID as randomUUID4 } from "crypto";
386243
+ import { randomUUID as randomUUID5 } from "crypto";
386227
386244
  function planSharedPull(state, now) {
386228
386245
  const expired = state.leases.find((lease) => lease.expiresAt <= now);
386229
386246
  return expired ? { reclaim: expired } : { after: state.claimed };
@@ -386408,7 +386425,7 @@ class EventConsumerService {
386408
386425
  const last = scanned[scanned.length - 1];
386409
386426
  if (!plan.reclaim && !last)
386410
386427
  return { consumer, lease: null, scanned };
386411
- const lease = plan.reclaim ? { ...plan.reclaim, id: randomUUID4(), expiresAt: now + leaseMs } : { id: randomUUID4(), from: plan.after, to: Number(last?.journalSeq), expiresAt: now + leaseMs };
386428
+ const lease = plan.reclaim ? { ...plan.reclaim, id: randomUUID5(), expiresAt: now + leaseMs } : { id: randomUUID5(), from: plan.after, to: Number(last?.journalSeq), expiresAt: now + leaseMs };
386412
386429
  if (await this.casLeaseState(consumer, claimLease(state, lease, plan.reclaim?.id))) {
386413
386430
  return { consumer, lease, scanned };
386414
386431
  }
@@ -387728,7 +387745,7 @@ var init_instances = __esm(() => {
387728
387745
  });
387729
387746
 
387730
387747
  // ../api/src/services/manifest-compiler.ts
387731
- import { createHash as createHash16 } from "crypto";
387748
+ import { createHash as createHash17 } from "crypto";
387732
387749
  function stableStringify(value) {
387733
387750
  if (Array.isArray(value)) {
387734
387751
  return `[${value.map((item) => stableStringify(item)).join(",")}]`;
@@ -387748,7 +387765,7 @@ function filterToConditions(filter) {
387748
387765
  return fields.map((field) => ({ field, operator: "eq", value: filter[field] }));
387749
387766
  }
387750
387767
  function compiledAutomationName(agentId, entry) {
387751
- const digest = createHash16("sha256").update(stableStringify({ event: entry.event, filter: entry.filter ?? null })).digest("hex").slice(0, 12);
387768
+ const digest = createHash17("sha256").update(stableStringify({ event: entry.event, filter: entry.filter ?? null })).digest("hex").slice(0, 12);
387752
387769
  const prefix = `manifest:${agentId}:`;
387753
387770
  const suffix = `#${digest}`;
387754
387771
  const room = MAX_AUTOMATION_NAME_LENGTH - prefix.length - suffix.length;
@@ -391419,9 +391436,9 @@ var init_turns = __esm(() => {
391419
391436
  });
391420
391437
 
391421
391438
  // ../api/src/lib/ingress-idempotency.ts
391422
- import { createHash as createHash17 } from "crypto";
391439
+ import { createHash as createHash18 } from "crypto";
391423
391440
  function sha256Hex(input) {
391424
- return createHash17("sha256").update(input).digest("hex");
391441
+ return createHash18("sha256").update(input).digest("hex");
391425
391442
  }
391426
391443
  function resolvePayloadPath(payload, path3) {
391427
391444
  let current = payload;
@@ -396935,6 +396952,30 @@ var init_health3 = __esm(() => {
396935
396952
 
396936
396953
  // ../api/src/schemas/openapi/instances.ts
396937
396954
  function registerInstanceSchemas(registry4) {
396955
+ const pathId = exports_external.object({ id: exports_external.string().uuid() });
396956
+ for (const [method, path3, schema3] of [
396957
+ ["get", "/instances/{id}/self", SelfIdentitySchema],
396958
+ ["post", "/instances/{id}/self/messages", SelfMessagesSchema],
396959
+ ["post", "/instances/{id}/self/history", SelfHistorySchema],
396960
+ ["post", "/instances/{id}/self/receipt", SelfReceiptSchema],
396961
+ ["get", "/instances/{id}/self/chats", SelfChatsSchema],
396962
+ ["post", "/messages/send-self", SendSelfSchema]
396963
+ ])
396964
+ registry4.registerPath({
396965
+ method,
396966
+ path: path3,
396967
+ tags: ["WhatsApp self"],
396968
+ request: {
396969
+ ...path3.includes("{id}") ? { params: pathId } : {},
396970
+ ...method === "get" && path3 === "/instances/{id}/self/chats" ? { query: SelfChatsSchema } : {},
396971
+ ...method === "post" ? { body: { content: { "application/json": { schema: schema3 } } } } : {}
396972
+ },
396973
+ responses: {
396974
+ 200: { description: "Verified bounded self capability" },
396975
+ 201: { description: "Native self send accepted" },
396976
+ 409: { description: "Identity changed or unverified" }
396977
+ }
396978
+ });
396938
396979
  registry4.register("Instance", InstanceSchema2);
396939
396980
  registry4.register("CreateInstanceRequest", CreateInstanceSchema2);
396940
396981
  registry4.register("InstanceStatus", InstanceStatusSchema2);
@@ -397493,7 +397534,7 @@ function registerInstanceSchemas(registry4) {
397493
397534
  }
397494
397535
  });
397495
397536
  }
397496
- var gupshupHandoffFieldValue, gupshupHandoffFieldKey, gupshupHandoffFields, GupshupHandoffOptionsSchema, closeContactOutcomeOverride, CloseContactConfigSchema, InstanceSchema2, CreateInstanceSchema2, InstanceStatusSchema2, QrCodeSchema, PairingCodeRequestSchema, PairingCodeSchema, ConnectInstanceSchema, ConnectResponseSchema, UserProfileSchema, ContactSchema, GroupSchema, SupportedChannelSchema;
397537
+ var gupshupHandoffFieldValue, gupshupHandoffFieldKey, gupshupHandoffFields, GupshupHandoffOptionsSchema, closeContactOutcomeOverride, CloseContactConfigSchema, InstanceSchema2, CreateInstanceSchema2, InstanceStatusSchema2, QrCodeSchema, PairingCodeRequestSchema, PairingCodeSchema, ConnectInstanceSchema, ConnectResponseSchema, UserProfileSchema, ContactSchema, GroupSchema, SupportedChannelSchema, ownJid, SelfIdentitySchema, selfWindow, validWindow = (v2) => Date.parse(v2.before) >= Date.parse(v2.after) && Date.parse(v2.before) - Date.parse(v2.after) <= 7 * 86400000, SelfMessagesSchema, SelfHistorySchema, SelfChatsSchema, SelfReceiptSchema, SendSelfSchema;
397497
397538
  var init_instances2 = __esm(() => {
397498
397539
  init_src();
397499
397540
  init_zod_openapi();
@@ -397677,6 +397718,34 @@ var init_instances2 = __esm(() => {
397677
397718
  loaded: exports_external.boolean().openapi({ description: "Whether plugin is loaded" }),
397678
397719
  capabilities: exports_external.record(exports_external.string(), exports_external.unknown()).optional().openapi({ description: "Plugin capabilities" })
397679
397720
  });
397721
+ ownJid = exports_external.string().regex(/^\d{5,20}@s\.whatsapp\.net$/);
397722
+ SelfIdentitySchema = exports_external.object({
397723
+ ownerIdentifier: ownJid,
397724
+ generation: exports_external.string().uuid(),
397725
+ selfJid: ownJid,
397726
+ connectedAt: exports_external.string().datetime()
397727
+ }).strict();
397728
+ selfWindow = {
397729
+ expectedOwner: ownJid,
397730
+ expectedGeneration: exports_external.string().uuid(),
397731
+ after: exports_external.string().datetime(),
397732
+ before: exports_external.string().datetime()
397733
+ };
397734
+ SelfMessagesSchema = exports_external.object({
397735
+ ...selfWindow,
397736
+ connectionStartedAt: exports_external.string().datetime(),
397737
+ excludeExternalIds: exports_external.array(exports_external.string().min(1).max(255)).max(1000).refine((v2) => new Set(v2).size === v2.length)
397738
+ }).strict().refine(validWindow, "At most seven days").refine((v2) => Date.parse(v2.connectionStartedAt) <= Date.parse(v2.after) && Date.parse(v2.after) === Math.max(Date.parse(v2.connectionStartedAt), Date.parse(v2.before) - 7 * 86400000), "Anchored self inbox window");
397739
+ SelfHistorySchema = exports_external.object({ ...selfWindow, chatId: exports_external.string().uuid() }).strict().refine(validWindow, "At most seven days");
397740
+ SelfChatsSchema = exports_external.object({ cursor: exports_external.string().uuid().optional() }).strict();
397741
+ SelfReceiptSchema = exports_external.object({ expectedOwner: ownJid, expectedGeneration: exports_external.string().uuid(), externalId: exports_external.string().min(1).max(255) }).strict();
397742
+ SendSelfSchema = exports_external.object({
397743
+ instanceId: exports_external.string().uuid(),
397744
+ expectedOwner: ownJid,
397745
+ expectedGeneration: exports_external.string().uuid(),
397746
+ operationKey: exports_external.string().regex(/^[A-Za-z0-9_-]{1,100}$/),
397747
+ text: exports_external.string().min(1).max(8000)
397748
+ }).strict();
397680
397749
  });
397681
397750
 
397682
397751
  // ../api/src/schemas/openapi/journeys.ts
@@ -405062,6 +405131,143 @@ var init_agent_replay = __esm(() => {
405062
405131
  MAX_REPLAY_WINDOW_MS = 24 * 60 * 60 * 1000;
405063
405132
  });
405064
405133
 
405134
+ // ../api/src/services/whatsapp-self.ts
405135
+ function selfPlugin(plugin13) {
405136
+ if (!plugin13 || plugin13.id !== "whatsapp-baileys" || !("getSelfIdentity" in plugin13) || typeof plugin13.getSelfIdentity !== "function" || !("sendSelf" in plugin13) || typeof plugin13.sendSelf !== "function")
405137
+ throw new Error("Self capability unavailable");
405138
+ return plugin13;
405139
+ }
405140
+ function verifySelf(plugin13, instanceId, expected) {
405141
+ const value = SelfIdentitySchema.parse(plugin13.getSelfIdentity(instanceId));
405142
+ if (value.selfJid !== value.ownerIdentifier || expected && (value.ownerIdentifier !== expected.expectedOwner || value.generation !== expected.expectedGeneration))
405143
+ throw new Error("Self identity changed");
405144
+ return value;
405145
+ }
405146
+ function freshInboxWindow(input) {
405147
+ const now = Date.now();
405148
+ const before = Date.parse(input.before);
405149
+ const after = Date.parse(input.after);
405150
+ const connectionStartedAt = Date.parse(input.connectionStartedAt);
405151
+ if (before < now - 60000 || before > now + 60000 || connectionStartedAt > after || after > before || before - after > 7 * 86400000 || after !== Math.max(connectionStartedAt, before - 7 * 86400000))
405152
+ throw new Error("Read window expired");
405153
+ }
405154
+ function platformTime(value) {
405155
+ let seconds;
405156
+ if (typeof value === "number")
405157
+ seconds = value;
405158
+ else {
405159
+ if (!value || typeof value !== "object" || Array.isArray(value))
405160
+ return null;
405161
+ const long = value;
405162
+ if (Object.keys(long).length !== 3 || Object.keys(long).some((key) => !["low", "high", "unsigned"].includes(key)) || typeof long.low !== "number" || !Number.isInteger(long.low) || long.low < -2147483648 || long.low > 2147483647 || typeof long.high !== "number" || !Number.isInteger(long.high) || long.high < -2147483648 || long.high > 2147483647 || typeof long.unsigned !== "boolean")
405163
+ return null;
405164
+ let integer3 = BigInt(long.high >>> 0) << 32n | BigInt(long.low >>> 0);
405165
+ if (!long.unsigned && long.high < 0)
405166
+ integer3 -= 1n << 64n;
405167
+ if (integer3 <= 0n || integer3 > 8640000000000n)
405168
+ return null;
405169
+ seconds = Number(integer3);
405170
+ }
405171
+ if (!Number.isSafeInteger(seconds) || seconds <= 0 || seconds > 8640000000000)
405172
+ return null;
405173
+ return new Date(seconds * 1000).toISOString();
405174
+ }
405175
+ function projectSelfEvent(row, owner, source = null) {
405176
+ const raw2 = row.rawPayload ?? {};
405177
+ const key = raw2.key;
405178
+ const message2 = raw2.message;
405179
+ const extended = message2?.extendedTextMessage;
405180
+ const context20 = extended?.contextInfo;
405181
+ const nativeText = message2?.conversation ?? extended?.text;
405182
+ const at = platformTime(raw2.messageTimestamp);
405183
+ const authority = source === "realtime" && row.eventType === "message.received" && row.contentType === "text" && key?.fromMe === true && raw2.isFromMe === true && key.remoteJid === owner && row.metadata?.from === owner.split("@")[0] && typeof nativeText === "string" && nativeText === row.textContent && at !== null && !row.replyToExternalId && !raw2.quotedMessage && !context20?.quotedMessage && !context20?.isForwarded && !context20?.forwardingScore && !message2?.protocolMessage && raw2.isHistorySync !== true;
405184
+ return {
405185
+ id: row.id,
405186
+ externalId: row.externalId,
405187
+ chatId: row.chatId,
405188
+ from: owner,
405189
+ text: row.textContent ?? "",
405190
+ at,
405191
+ receivedAt: row.receivedAt.toISOString(),
405192
+ isFromMe: raw2.isFromMe === true,
405193
+ authority
405194
+ };
405195
+ }
405196
+ async function readSelfMessages(db2, plugin13, instanceId, input) {
405197
+ const identity = verifySelf(plugin13, instanceId, input);
405198
+ freshInboxWindow(input);
405199
+ const rows = await db2.select({ event: omniEvents, source: messages2.source }).from(omniEvents).innerJoin(chats, and2(eq(chats.instanceId, omniEvents.instanceId), eq(chats.externalId, omniEvents.chatId))).innerJoin(messages2, and2(eq(messages2.chatId, chats.id), eq(messages2.externalId, omniEvents.externalId))).where(and2(eq(omniEvents.instanceId, instanceId), eq(omniEvents.chatId, identity.selfJid), eq(omniEvents.eventType, "message.received"), eq(omniEvents.contentType, "text"), eq(messages2.source, "realtime"), eq(messages2.isFromMe, true), isNull2(chats.deletedAt), isNull2(messages2.deletedAt), isNotNull(omniEvents.externalId), gte(omniEvents.receivedAt, new Date(input.after)), lte(omniEvents.receivedAt, new Date(input.before)), input.excludeExternalIds.length ? notInArray(omniEvents.externalId, input.excludeExternalIds) : undefined)).orderBy(asc(omniEvents.receivedAt), asc(omniEvents.id)).limit(51);
405200
+ const older = await db2.select({ id: omniEvents.id }).from(omniEvents).innerJoin(chats, and2(eq(chats.instanceId, omniEvents.instanceId), eq(chats.externalId, omniEvents.chatId))).innerJoin(messages2, and2(eq(messages2.chatId, chats.id), eq(messages2.externalId, omniEvents.externalId))).where(and2(eq(omniEvents.instanceId, instanceId), eq(omniEvents.chatId, identity.selfJid), eq(omniEvents.eventType, "message.received"), eq(omniEvents.contentType, "text"), eq(messages2.source, "realtime"), eq(messages2.isFromMe, true), isNull2(chats.deletedAt), isNull2(messages2.deletedAt), isNotNull(omniEvents.externalId), gte(omniEvents.receivedAt, new Date(input.connectionStartedAt)), lt(omniEvents.receivedAt, new Date(input.after)), input.excludeExternalIds.length ? notInArray(omniEvents.externalId, input.excludeExternalIds) : undefined)).limit(1);
405201
+ verifySelf(plugin13, instanceId, input);
405202
+ return {
405203
+ items: rows.slice(0, 50).map((row) => {
405204
+ const projected = projectSelfEvent(row.event, identity.selfJid, row.source);
405205
+ projected.authority = projected.authority && projected.at !== null && Date.parse(projected.at) >= Date.parse(input.connectionStartedAt) && Date.parse(projected.at) <= Date.parse(input.before);
405206
+ return projected;
405207
+ }),
405208
+ hasMore: rows.length > 50,
405209
+ hasOlder: older.length > 0
405210
+ };
405211
+ }
405212
+ async function readOwnedChats(db2, plugin13, instanceId, cursor) {
405213
+ const identity = verifySelf(plugin13, instanceId);
405214
+ const rows = await db2.select({ id: chats.id, name: chats.name }).from(chats).where(and2(eq(chats.instanceId, instanceId), isNull2(chats.deletedAt), cursor ? gt(chats.id, cursor) : undefined)).orderBy(asc(chats.id)).limit(26);
405215
+ verifySelf(plugin13, instanceId, { expectedOwner: identity.ownerIdentifier, expectedGeneration: identity.generation });
405216
+ const items = rows.slice(0, 25);
405217
+ return { items, meta: { hasMore: rows.length > 25, cursor: rows.length > 25 ? items.at(-1)?.id ?? null : null } };
405218
+ }
405219
+ function boundHistory(rows) {
405220
+ let characters = 0;
405221
+ let partial = rows.length > 50;
405222
+ const items = [];
405223
+ for (const row of rows.slice(0, 50)) {
405224
+ const text3 = row.text ?? "";
405225
+ if (characters + text3.length > 8000) {
405226
+ partial = true;
405227
+ break;
405228
+ }
405229
+ characters += text3.length;
405230
+ items.push({
405231
+ externalId: row.externalId,
405232
+ text: text3,
405233
+ at: row.at.toISOString(),
405234
+ direction: row.isFromMe ? "outbound" : "inbound"
405235
+ });
405236
+ }
405237
+ return { items, partial, limits: { days: 7, messages: 50, characters: 8000 } };
405238
+ }
405239
+ async function readOwnedHistory(db2, plugin13, instanceId, input) {
405240
+ verifySelf(plugin13, instanceId, input);
405241
+ const rows = await db2.select({
405242
+ externalId: messages2.externalId,
405243
+ text: messages2.textContent,
405244
+ at: messages2.platformTimestamp,
405245
+ isFromMe: messages2.isFromMe
405246
+ }).from(messages2).innerJoin(chats, eq(chats.id, messages2.chatId)).where(and2(eq(chats.id, input.chatId), eq(chats.instanceId, instanceId), isNull2(chats.deletedAt), isNull2(messages2.deletedAt), gte(messages2.platformTimestamp, new Date(input.after)), lte(messages2.platformTimestamp, new Date(input.before)))).orderBy(desc(messages2.platformTimestamp), desc(messages2.id)).limit(51);
405247
+ const [chat2] = await db2.select({ id: chats.id }).from(chats).where(and2(eq(chats.id, input.chatId), eq(chats.instanceId, instanceId), isNull2(chats.deletedAt))).limit(1);
405248
+ if (!chat2)
405249
+ throw new Error("Selected chat unavailable");
405250
+ verifySelf(plugin13, instanceId, input);
405251
+ return boundHistory(rows);
405252
+ }
405253
+ async function readSelfReceipt(db2, plugin13, instanceId, input) {
405254
+ const identity = verifySelf(plugin13, instanceId, input);
405255
+ const [row] = await db2.select({ externalId: messages2.externalId, text: messages2.textContent, at: messages2.platformTimestamp }).from(messages2).innerJoin(chats, eq(chats.id, messages2.chatId)).innerJoin(omniEvents, and2(eq(omniEvents.externalId, messages2.externalId), eq(omniEvents.instanceId, instanceId), eq(omniEvents.chatId, identity.selfJid))).where(and2(eq(chats.instanceId, instanceId), eq(chats.externalId, identity.selfJid), eq(messages2.externalId, input.externalId), eq(messages2.source, "realtime"), eq(omniEvents.eventType, "message.sent"), eq(omniEvents.direction, "outbound"), eq(omniEvents.status, "completed"), eq(omniEvents.contentType, "text"), eq(messages2.messageType, "text"), eq(messages2.textContent, omniEvents.textContent), eq(messages2.isFromMe, true), isNull2(messages2.deletedAt))).limit(1);
405256
+ verifySelf(plugin13, instanceId, input);
405257
+ return row ? {
405258
+ externalId: row.externalId,
405259
+ text: row.text ?? "",
405260
+ at: row.at.toISOString(),
405261
+ ownerIdentifier: identity.ownerIdentifier,
405262
+ generation: identity.generation
405263
+ } : null;
405264
+ }
405265
+ var init_whatsapp_self = __esm(() => {
405266
+ init_src6();
405267
+ init_drizzle_orm();
405268
+ init_instances2();
405269
+ });
405270
+
405065
405271
  // ../api/src/routes/v2/instances.ts
405066
405272
  function shouldApplyDefaultReplyFilter(args) {
405067
405273
  if (!args.agentIdTouched)
@@ -405657,6 +405863,7 @@ var init_instances3 = __esm(() => {
405657
405863
  init_instances2();
405658
405864
  init_access();
405659
405865
  init_agent_replay();
405866
+ init_whatsapp_self();
405660
405867
  log123 = createLogger("api:instances");
405661
405868
  instancesRoutes = new Hono2;
405662
405869
  instanceAccess3 = requireInstanceAccess((c) => c.req.param("id") ?? "");
@@ -406018,6 +406225,51 @@ var init_instances3 = __esm(() => {
406018
406225
  }
406019
406226
  return c.json({ success: true });
406020
406227
  });
406228
+ instancesRoutes.get("/:id/self", instanceAccess3, async (c) => {
406229
+ try {
406230
+ const instance4 = await c.get("services").instances.getById(c.req.param("id"));
406231
+ const plugin13 = selfPlugin(c.get("channelRegistry")?.get(instance4.channel));
406232
+ return c.json({ data: verifySelf(plugin13, instance4.id) });
406233
+ } catch {
406234
+ return c.json({ error: { code: "SELF_UNAVAILABLE" } }, 409);
406235
+ }
406236
+ });
406237
+ instancesRoutes.get("/:id/self/chats", instanceAccess3, zValidator("query", SelfChatsSchema), async (c) => {
406238
+ try {
406239
+ const instance4 = await c.get("services").instances.getById(c.req.param("id"));
406240
+ const plugin13 = selfPlugin(c.get("channelRegistry")?.get(instance4.channel));
406241
+ return c.json(await readOwnedChats(c.get("db"), plugin13, instance4.id, c.req.valid("query").cursor));
406242
+ } catch {
406243
+ return c.json({ error: { code: "SELF_READ_UNAVAILABLE" } }, 409);
406244
+ }
406245
+ });
406246
+ instancesRoutes.post("/:id/self/messages", instanceAccess3, zValidator("json", SelfMessagesSchema), async (c) => {
406247
+ try {
406248
+ const instance4 = await c.get("services").instances.getById(c.req.param("id"));
406249
+ const plugin13 = selfPlugin(c.get("channelRegistry")?.get(instance4.channel));
406250
+ return c.json(await readSelfMessages(c.get("db"), plugin13, instance4.id, c.req.valid("json")));
406251
+ } catch {
406252
+ return c.json({ error: { code: "SELF_READ_UNAVAILABLE" } }, 409);
406253
+ }
406254
+ });
406255
+ instancesRoutes.post("/:id/self/receipt", instanceAccess3, zValidator("json", SelfReceiptSchema), async (c) => {
406256
+ try {
406257
+ const instance4 = await c.get("services").instances.getById(c.req.param("id"));
406258
+ const plugin13 = selfPlugin(c.get("channelRegistry")?.get(instance4.channel));
406259
+ return c.json({ data: await readSelfReceipt(c.get("db"), plugin13, instance4.id, c.req.valid("json")) });
406260
+ } catch {
406261
+ return c.json({ error: { code: "SELF_READ_UNAVAILABLE" } }, 409);
406262
+ }
406263
+ });
406264
+ instancesRoutes.post("/:id/self/history", instanceAccess3, zValidator("json", SelfHistorySchema), async (c) => {
406265
+ try {
406266
+ const instance4 = await c.get("services").instances.getById(c.req.param("id"));
406267
+ const plugin13 = selfPlugin(c.get("channelRegistry")?.get(instance4.channel));
406268
+ return c.json(await readOwnedHistory(c.get("db"), plugin13, instance4.id, c.req.valid("json")));
406269
+ } catch {
406270
+ return c.json({ error: { code: "SELF_READ_UNAVAILABLE" } }, 409);
406271
+ }
406272
+ });
406021
406273
  instancesRoutes.get("/:id/status", instanceAccess3, async (c) => {
406022
406274
  const id = c.req.param("id");
406023
406275
  const services = c.get("services");
@@ -409916,9 +410168,11 @@ var init_messages6 = __esm(() => {
409916
410168
  init_sentry_scrub();
409917
410169
  init_media_processor();
409918
410170
  init_date_query();
410171
+ init_instances2();
409919
410172
  init_messages5();
409920
410173
  init_api_keys();
409921
410174
  init_media_storage();
410175
+ init_whatsapp_self();
409922
410176
  init_tenant_scope();
409923
410177
  init__close_contact_config();
409924
410178
  log126 = createLogger("routes:messages");
@@ -410348,6 +410602,21 @@ var init_messages6 = __esm(() => {
410348
410602
  const message2 = await services.messages.updateDocumentExtraction(id, extraction);
410349
410603
  return c.json({ data: message2 });
410350
410604
  });
410605
+ messagesRoutes.post("/send-self", zValidator("json", SendSelfSchema), async (c) => {
410606
+ const { instanceId, ...input } = c.req.valid("json");
410607
+ checkInstanceAccess2(c.get("apiKey"), instanceId);
410608
+ try {
410609
+ const instance4 = await c.get("services").instances.getById(instanceId);
410610
+ const plugin13 = selfPlugin(c.get("channelRegistry")?.get(instance4.channel));
410611
+ verifySelf(plugin13, instanceId, input);
410612
+ const text3 = sanitizeOutboundText(input.text);
410613
+ if (!text3.trim())
410614
+ return c.json({ error: { code: "SELF_TEXT_REQUIRED" } }, 400);
410615
+ return c.json({ data: await plugin13.sendSelf(instanceId, { ...input, text: text3 }) }, 201);
410616
+ } catch {
410617
+ return c.json({ error: { code: "SELF_SEND_UNCONFIRMED" } }, 409);
410618
+ }
410619
+ });
410351
410620
  messagesRoutes.post("/send", async (c) => {
410352
410621
  let rawBody;
410353
410622
  try {
@@ -412562,7 +412831,7 @@ var init_settings3 = __esm(() => {
412562
412831
  });
412563
412832
 
412564
412833
  // ../api/src/lib/single-use-store.ts
412565
- import { randomUUID as randomUUID5 } from "crypto";
412834
+ import { randomUUID as randomUUID6 } from "crypto";
412566
412835
  function createSingleUseStore(opts) {
412567
412836
  const { ttlMs, maxEntries, prefix } = opts;
412568
412837
  if (!(ttlMs > 0))
@@ -412601,7 +412870,7 @@ function createSingleUseStore(opts) {
412601
412870
  }
412602
412871
  return {
412603
412872
  put(value, entryTtlMs = ttlMs) {
412604
- const handle = `${prefix}${randomUUID5()}`;
412873
+ const handle = `${prefix}${randomUUID6()}`;
412605
412874
  const expiresAt = Date.now() + entryTtlMs;
412606
412875
  remember(handle, expiresAt);
412607
412876
  store(handle, value, expiresAt);
@@ -430754,6 +431023,7 @@ var src_default8 = plugin9;
430754
431023
  // ../channel-whatsapp/src/plugin.ts
430755
431024
  init_src2();
430756
431025
  init_src();
431026
+ import { createHash as createHash12, randomUUID as randomUUID2 } from "crypto";
430757
431027
 
430758
431028
  // ../channel-whatsapp/src/auth.ts
430759
431029
  init_src();
@@ -545092,6 +545362,15 @@ function createRateLimitManager(instanceId, logger5, config2) {
545092
545362
  }
545093
545363
 
545094
545364
  // ../channel-whatsapp/src/plugin.ts
545365
+ function selfPlatformMessageId(instanceId, owner, operationKey) {
545366
+ return `3EB0${createHash12("sha256").update(JSON.stringify([instanceId, owner, operationKey])).digest("hex").slice(0, 32).toUpperCase()}`;
545367
+ }
545368
+ function ownPhoneJid(value) {
545369
+ if (typeof value !== "string" || !/^\d{5,20}(?::\d+)?@s\.whatsapp\.net$/.test(value)) {
545370
+ throw new WhatsAppError(ErrorCode2.NOT_CONNECTED, "Verified own phone identity required");
545371
+ }
545372
+ return value.replace(/:\d+@/, "@");
545373
+ }
545095
545374
  function isTransientConnectionClosedError(error) {
545096
545375
  if (!error)
545097
545376
  return false;
@@ -545124,6 +545403,8 @@ class WhatsAppPlugin extends BaseChannelPlugin {
545124
545403
  version = "1.0.0";
545125
545404
  capabilities = WHATSAPP_CAPABILITIES;
545126
545405
  sockets = new Map;
545406
+ selfGenerations = new WeakMap;
545407
+ selfConnectedAt = new WeakMap;
545127
545408
  passkeyStates = new Map;
545128
545409
  pluginConfig = {};
545129
545410
  historySyncCallbacks = new Map;
@@ -545916,6 +546197,45 @@ class WhatsAppPlugin extends BaseChannelPlugin {
545916
546197
  systemNotice: originalMessage.metadata?.systemNotice
545917
546198
  };
545918
546199
  }
546200
+ getSelfIdentity(instanceId) {
546201
+ const sock = this.getSocket(instanceId);
546202
+ if (this.instances.getStatus(instanceId)?.state !== "connected") {
546203
+ throw new WhatsAppError(ErrorCode2.NOT_CONNECTED, "WhatsApp is disconnected");
546204
+ }
546205
+ const ownerIdentifier = ownPhoneJid(sock.user?.id);
546206
+ const generation = this.selfGenerations.get(sock);
546207
+ const connectedAt = this.selfConnectedAt.get(sock);
546208
+ if (!generation || !connectedAt)
546209
+ throw new Error("Authenticated connection epoch unavailable");
546210
+ return { ownerIdentifier, generation, selfJid: ownerIdentifier, connectedAt };
546211
+ }
546212
+ async sendSelf(instanceId, input) {
546213
+ if (Object.keys(input).some((key) => !["expectedOwner", "expectedGeneration", "operationKey", "text"].includes(key)) || !/^[A-Za-z0-9_-]{1,100}$/.test(input.operationKey) || typeof input.text !== "string" || !input.text.trim() || input.text.length > 8000)
546214
+ throw new Error("Invalid self message");
546215
+ const sock = this.getSocket(instanceId);
546216
+ const admitted = this.getSelfIdentity(instanceId);
546217
+ if (admitted.ownerIdentifier !== input.expectedOwner || admitted.generation !== input.expectedGeneration)
546218
+ throw new Error("Self identity changed");
546219
+ const externalId = selfPlatformMessageId(instanceId, admitted.ownerIdentifier, input.operationKey);
546220
+ const limiter = await this.waitForRateLimitBackoff(instanceId);
546221
+ const message2 = {
546222
+ to: admitted.selfJid,
546223
+ content: { type: "text", text: input.text },
546224
+ metadata: { correlationId: input.operationKey }
546225
+ };
546226
+ this.trackSentMessageId(instanceId, externalId);
546227
+ const current = this.getSelfIdentity(instanceId);
546228
+ if (this.sockets.get(instanceId) !== sock || current.ownerIdentifier !== admitted.ownerIdentifier || current.generation !== admitted.generation)
546229
+ throw new Error("Self identity changed");
546230
+ const result = await sock.sendMessage(admitted.selfJid, { text: input.text }, { messageId: externalId });
546231
+ if (result?.key?.id !== externalId)
546232
+ throw new Error("Self send outcome is uncertain");
546233
+ if (result.message)
546234
+ this.trackRecentSentMessage(instanceId, externalId, result.message);
546235
+ await this.emitMessageSent(this.buildSentEventPayload(instanceId, externalId, admitted.selfJid, message2, message2));
546236
+ limiter.reset();
546237
+ return { externalId, ownerIdentifier: admitted.ownerIdentifier, generation: admitted.generation };
546238
+ }
545919
546239
  async sendMessage(instanceId, message2) {
545920
546240
  const sock = this.getSocket(instanceId);
545921
546241
  const jid = await this.resolveSendTarget(sock, instanceId, message2.to);
@@ -546657,6 +546977,13 @@ class WhatsAppPlugin extends BaseChannelPlugin {
546657
546977
  }
546658
546978
  }
546659
546979
  async handleConnected(instanceId, sock, isNewLogin = false) {
546980
+ try {
546981
+ ownPhoneJid(sock.user?.id);
546982
+ if (!this.selfConnectedAt.has(sock))
546983
+ this.selfConnectedAt.set(sock, new Date().toISOString());
546984
+ if (!this.selfGenerations.has(sock))
546985
+ this.selfGenerations.set(sock, randomUUID2());
546986
+ } catch {}
546660
546987
  this.passkeyStates.delete(instanceId);
546661
546988
  let profileName;
546662
546989
  let profilePicUrl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.261006.2",
3
+ "version": "2.261008.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/automagik-dev/omni.git",