@almadar/integrations 2.25.0 → 2.27.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.
@@ -1,5 +1,5 @@
1
1
  import { ServiceParamsValue, ServiceParams, EntityRow } from '@almadar/core';
2
- import { d as IntegrationParamValue, e as IntegrationParams } from './BaseIntegration-MA-b4fh8.js';
2
+ import { f as IntegrationParamValue, g as IntegrationParams } from './BaseIntegration-C_5q54DM.js';
3
3
 
4
4
  /** Scalar value admissible as a SQL bind parameter. */
5
5
  type DatabaseQueryParamValue = string | number | boolean | Date | null;
@@ -323,6 +323,7 @@ type TwilioActions = {
323
323
  params: {
324
324
  to: string;
325
325
  body: string;
326
+ from?: string;
326
327
  };
327
328
  result: {
328
329
  sid: string;
@@ -347,6 +348,11 @@ type EmailActions = {
347
348
  subject: string;
348
349
  body: string;
349
350
  from?: string;
351
+ /** HTML content; when present `body` becomes the plain-text alternative. */
352
+ htmlBody?: string;
353
+ replyTo?: string;
354
+ /** Provider template reference (SendGrid dynamic templates; Resend rejects it loudly). */
355
+ templateId?: string;
350
356
  };
351
357
  result: {
352
358
  id: string;
@@ -857,6 +863,7 @@ type StorageActions = {
857
863
  bucket: string;
858
864
  prefix?: string;
859
865
  maxKeys?: number;
866
+ continuationToken?: string;
860
867
  };
861
868
  result: {
862
869
  keys: Array<{
@@ -865,6 +872,7 @@ type StorageActions = {
865
872
  lastModified: number;
866
873
  }>;
867
874
  truncated: boolean;
875
+ nextToken?: string;
868
876
  };
869
877
  };
870
878
  delete: {
@@ -1154,6 +1162,14 @@ type CredentialsActions = {
1154
1162
  message: string;
1155
1163
  };
1156
1164
  };
1165
+ rotate: {
1166
+ params: Record<string, never>;
1167
+ result: {
1168
+ rotated: number;
1169
+ alreadyCurrent: number;
1170
+ unreadable: number;
1171
+ };
1172
+ };
1157
1173
  };
1158
1174
  type OtelActions = {
1159
1175
  startSpan: {
@@ -1414,6 +1430,34 @@ type IntegrationName = keyof IntegrationContracts;
1414
1430
  * ```
1415
1431
  */
1416
1432
  type IntegrationActionName<K extends IntegrationName> = keyof IntegrationContracts[K] & string;
1433
+ /**
1434
+ * Declared side-effect-free "Test connection" probes, executed by the
1435
+ * `credentials.test` action through the normal factory path. Only services
1436
+ * with a genuinely cheap, read-only, env-defaulted action carry one; the
1437
+ * rest report credential presence + constructor validation.
1438
+ */
1439
+ /**
1440
+ * One inbound-hook mount a service's provider needs in a deployed app:
1441
+ * `POST /api/hooks/:provider` verified by the provider's own token/signature,
1442
+ * dispatching `event` onto the app bus. A hook is a PROVIDER property — the
1443
+ * service invocation is the `.lolo` surface; codegen derives the mount from
1444
+ * the app's invoked services × these declarations (I-26).
1445
+ */
1446
+ interface HookDeclaration {
1447
+ /** Provider key mounted at POST /api/hooks/:provider */
1448
+ provider: string;
1449
+ /** Bus event dispatched into the app on a verified callback */
1450
+ event: string;
1451
+ /** Env var carrying the provider's verification secret/channel token */
1452
+ credentialEnv: string;
1453
+ /** Factory export in @almadar/integrations: (secret?) => HookProvider */
1454
+ providerExport: string;
1455
+ }
1456
+ /**
1457
+ * Inbound-hook declarations per service — the single source the registry,
1458
+ * codegen, and the playground mount derive from.
1459
+ */
1460
+ declare const serviceHooks: Record<string, HookDeclaration[]>;
1417
1461
 
1418
1462
  /** Entity type the credential rows persist under (never a `.lolo`-declared entity). */
1419
1463
  declare const CREDENTIAL_ENTITY_TYPE = "AlmadarIntegrationCredential";
@@ -1457,17 +1501,26 @@ interface CredentialEntry {
1457
1501
  declare class CredentialStore {
1458
1502
  private readonly adapter;
1459
1503
  private readonly masterKeyHex;
1504
+ private readonly previousKeyHex;
1460
1505
  private readonly byEnvVar;
1461
1506
  private readonly listeners;
1462
1507
  private warmed;
1463
- constructor(adapter: CredentialPersistence, masterKey?: string);
1508
+ constructor(adapter: CredentialPersistence, masterKey?: string, previousMasterKey?: string);
1464
1509
  /** True when a valid master key is present (writes and decryption enabled). */
1465
1510
  get enabled(): boolean;
1466
1511
  /** Subscribe to credential changes; returns an unsubscribe function. */
1467
1512
  subscribe(listener: () => void): () => void;
1468
1513
  private notify;
1469
1514
  private encrypt;
1470
- private decrypt;
1515
+ private decryptWithKey;
1516
+ /**
1517
+ * Decrypt one row, selecting the key by the row's stamped `keyId` (I-28):
1518
+ * current key first, then the rotation-window previous key. Legacy rows
1519
+ * (no `keyId`) try current then previous. Returns null when no held key
1520
+ * decrypts the row — the row is unreadable, never silently wrong (GCM
1521
+ * auth tags make a wrong-key success impossible).
1522
+ */
1523
+ private decryptRow;
1471
1524
  /**
1472
1525
  * Load and decrypt every stored row into memory. Returns the number of
1473
1526
  * resolvable credentials. Without a master key nothing decrypts (rows are
@@ -1482,8 +1535,19 @@ declare class CredentialStore {
1482
1535
  entries(): CredentialEntry[];
1483
1536
  /** Upsert one credential (encrypts, persists, re-warms the entry, notifies). */
1484
1537
  set(service: string, envVar: string, value: string): Promise<CredentialEntry>;
1538
+ /**
1539
+ * Re-encrypt every readable row under the CURRENT master key (I-28).
1540
+ * Rotation window: deploy the new key as `ALMADAR_CREDENTIAL_MASTER_KEY`
1541
+ * with the old one as `..._PREVIOUS`, call `rotate()`, then retire the
1542
+ * previous key. Rows no held key can read are counted, never dropped.
1543
+ */
1544
+ rotate(): Promise<{
1545
+ rotated: number;
1546
+ alreadyCurrent: number;
1547
+ unreadable: number;
1548
+ }>;
1485
1549
  /** Delete one credential row; resolution falls back to env afterwards. */
1486
1550
  remove(envVar: string): Promise<boolean>;
1487
1551
  }
1488
1552
 
1489
- export { type ArxivActions as A, type CLIActions as C, type DatabaseActions as D, type EmailActions as E, type GitHubActions as G, type IconifyActions as I, type LLMIntegrationActions as L, type MLActions as M, type OAuthActions as O, type QueueActions as Q, type RedisActions as R, type StorageActions as S, type TwilioActions as T, type WebhookActions as W, type YouTubeActions as Y, CREDENTIAL_ENTITY_TYPE as a, CREDENTIAL_MASTER_KEY_ENV as b, type CredentialEntry as c, type CredentialPersistence as d, CredentialStore as e, type DatabaseDriver as f, type DatabaseQueryParamValue as g, type DatabaseQueryParams as h, type DatabaseQueryResult as i, type DatabaseRow as j, type DeepAgentActions as k, type DockerActions as l, type IntegrationActionName as m, type IntegrationContracts as n, type IntegrationName as o, type OtelActions as p, type StripeActions as q, type WikimediaActions as r };
1553
+ export { type ArxivActions as A, type CLIActions as C, type DatabaseActions as D, type EmailActions as E, type GitHubActions as G, type HookDeclaration as H, type IconifyActions as I, type LLMIntegrationActions as L, type MLActions as M, type OAuthActions as O, type QueueActions as Q, type RedisActions as R, type StorageActions as S, type TwilioActions as T, type WebhookActions as W, type YouTubeActions as Y, CREDENTIAL_ENTITY_TYPE as a, CREDENTIAL_MASTER_KEY_ENV as b, type CredentialEntry as c, type CredentialPersistence as d, CredentialStore as e, type DatabaseDriver as f, type DatabaseQueryParamValue as g, type DatabaseQueryParams as h, type DatabaseQueryResult as i, type DatabaseRow as j, type DeepAgentActions as k, type DockerActions as l, type IntegrationActionName as m, type IntegrationContracts as n, type IntegrationName as o, type OtelActions as p, type StripeActions as q, type WikimediaActions as r, serviceHooks as s };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/integrations",
3
- "version": "2.25.0",
3
+ "version": "2.27.0",
4
4
  "description": "External service integrations for Almadar applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@almadar/core": "^10.66.0",
36
+ "@almadar/core": "^10.68.0",
37
37
  "@almadar/llm": "^2.41.0",
38
38
  "@almadar/logger": "^1.11.0",
39
39
  "@aws-sdk/client-s3": "^3.700.0",
@@ -1,59 +0,0 @@
1
- import { I as IntegrationConfig, B as BaseIntegration, e as IntegrationParams, f as IntegrationResult } from './BaseIntegration-MA-b4fh8.js';
2
-
3
- /**
4
- * Optional per-call context for principal-scoped resolution (W4). The
5
- * default — absent — means the tenant/app-wide credential set; a `principal`
6
- * selects a per-principal configuration when one was registered. Additive:
7
- * every existing call site is untouched.
8
- */
9
- interface IntegrationCallContext {
10
- principal?: string;
11
- }
12
- /**
13
- * Factory for creating and managing integration instances
14
- */
15
- declare class IntegrationFactory {
16
- private instances;
17
- private configs;
18
- /**
19
- * Configure an integration (doesn't instantiate yet). A `principal` scopes
20
- * the config to that principal; the app-wide config (no principal) is the
21
- * fallback for every principal.
22
- */
23
- configure(name: string, config: Omit<IntegrationConfig, 'name'>, principal?: string): void;
24
- /**
25
- * Get or create an integration instance. Principal-scoped lookups fall
26
- * back to the app-wide config when no per-principal config exists.
27
- */
28
- get(name: string, principal?: string): BaseIntegration;
29
- /**
30
- * Execute an action on an integration
31
- */
32
- execute(integration: string, action: string, params: IntegrationParams, context?: IntegrationCallContext): Promise<IntegrationResult>;
33
- /**
34
- * Check if integration is configured
35
- */
36
- isConfigured(name: string, principal?: string): boolean;
37
- /**
38
- * Register an integration instance directly (used by mock infrastructure)
39
- */
40
- registerInstance(name: string, instance: BaseIntegration, principal?: string): void;
41
- /**
42
- * Drop the cached instance(s) for a name so the next `get` rebuilds from
43
- * the current config — how a credential change goes live without restart.
44
- * Configs are kept; without a name, every instance is dropped.
45
- */
46
- invalidate(name?: string): void;
47
- /**
48
- * Clear all instances (useful for testing)
49
- */
50
- clear(): void;
51
- /**
52
- * Clear all instances and configs
53
- */
54
- reset(): void;
55
- }
56
- declare function getIntegrationFactory(): IntegrationFactory;
57
- declare function resetIntegrationFactory(): void;
58
-
59
- export { type IntegrationCallContext as I, IntegrationFactory as a, getIntegrationFactory as g, resetIntegrationFactory as r };