@almadar/integrations 2.24.0 → 2.26.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.
@@ -117,6 +117,65 @@ interface ValidationError {
117
117
  */
118
118
  declare function validateParams(integration: string, action: string, params: IntegrationParams): ValidationResult;
119
119
 
120
+ /**
121
+ * Optional per-call context for principal-scoped resolution (W4) and
122
+ * caller-identity enforcement (I-25). The default — absent — means the
123
+ * tenant/app-wide credential set with an anonymous caller; role-gated
124
+ * integrations (credentials) fail closed without it. Additive: every
125
+ * existing call site is untouched.
126
+ */
127
+ interface IntegrationCallContext {
128
+ principal?: string;
129
+ /** The caller's roster role, from the same identity entity-ACL enforces against. */
130
+ role?: string;
131
+ }
132
+ /**
133
+ * Factory for creating and managing integration instances
134
+ */
135
+ declare class IntegrationFactory {
136
+ private instances;
137
+ private configs;
138
+ /**
139
+ * Configure an integration (doesn't instantiate yet). A `principal` scopes
140
+ * the config to that principal; the app-wide config (no principal) is the
141
+ * fallback for every principal.
142
+ */
143
+ configure(name: string, config: Omit<IntegrationConfig, 'name'>, principal?: string): void;
144
+ /**
145
+ * Get or create an integration instance. Principal-scoped lookups fall
146
+ * back to the app-wide config when no per-principal config exists.
147
+ */
148
+ get(name: string, principal?: string): BaseIntegration;
149
+ /**
150
+ * Execute an action on an integration
151
+ */
152
+ execute(integration: string, action: string, params: IntegrationParams, context?: IntegrationCallContext): Promise<IntegrationResult>;
153
+ /**
154
+ * Check if integration is configured
155
+ */
156
+ isConfigured(name: string, principal?: string): boolean;
157
+ /**
158
+ * Register an integration instance directly (used by mock infrastructure)
159
+ */
160
+ registerInstance(name: string, instance: BaseIntegration, principal?: string): void;
161
+ /**
162
+ * Drop the cached instance(s) for a name so the next `get` rebuilds from
163
+ * the current config — how a credential change goes live without restart.
164
+ * Configs are kept; without a name, every instance is dropped.
165
+ */
166
+ invalidate(name?: string): void;
167
+ /**
168
+ * Clear all instances (useful for testing)
169
+ */
170
+ clear(): void;
171
+ /**
172
+ * Clear all instances and configs
173
+ */
174
+ reset(): void;
175
+ }
176
+ declare function getIntegrationFactory(): IntegrationFactory;
177
+ declare function resetIntegrationFactory(): void;
178
+
120
179
  /**
121
180
  * Base class for all integrations
122
181
  */
@@ -125,9 +184,11 @@ declare abstract class BaseIntegration {
125
184
  protected logger: IntegrationLogger;
126
185
  constructor(config: IntegrationConfig);
127
186
  /**
128
- * Execute an action
187
+ * Execute an action. `context` carries the caller's identity when the host
188
+ * supplies one; integrations that gate actions by role read it and fail
189
+ * closed when it is absent.
129
190
  */
130
- abstract execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
191
+ abstract execute(action: string, params: IntegrationParams, context?: IntegrationCallContext): Promise<IntegrationResult>;
131
192
  /**
132
193
  * Validate action params against registry
133
194
  */
@@ -146,4 +207,4 @@ declare abstract class BaseIntegration {
146
207
  protected executeWithRetry<T>(fn: () => Promise<T>): Promise<T>;
147
208
  }
148
209
 
149
- export { BaseIntegration as B, type IntegrationConfig as I, type ValidationError as V, IntegrationError as a, type IntegrationErrorCode as b, type IntegrationLogger as c, type IntegrationParamValue as d, type IntegrationParams as e, type IntegrationResult as f, type ValidationResult as g, validateParams as v };
210
+ export { BaseIntegration as B, type IntegrationCallContext as I, type ValidationError as V, type IntegrationConfig as a, IntegrationError as b, type IntegrationErrorCode as c, IntegrationFactory as d, type IntegrationLogger as e, type IntegrationParamValue as f, type IntegrationParams as g, type IntegrationResult as h, type ValidationResult as i, getIntegrationFactory as j, resetIntegrationFactory as r, validateParams as v };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { c as IntegrationLogger, b as IntegrationErrorCode, I as IntegrationConfig, B as BaseIntegration, e as IntegrationParams, f as IntegrationResult } from './BaseIntegration-MA-b4fh8.js';
2
- export { a as IntegrationError, d as IntegrationParamValue, V as ValidationError, g as ValidationResult, v as validateParams } from './BaseIntegration-MA-b4fh8.js';
3
- export { A as ArxivActions, C as CLIActions, D as DatabaseActions, a as DatabaseDriver, b as DatabaseQueryParamValue, c as DatabaseQueryParams, d as DatabaseQueryResult, e as DatabaseRow, f as DeepAgentActions, g as DockerActions, E as EmailActions, G as GitHubActions, I as IconifyActions, h as IntegrationActionName, i as IntegrationContracts, j as IntegrationName, L as LLMIntegrationActions, M as MLActions, O as OAuthActions, k as OtelActions, Q as QueueActions, R as RedisActions, S as StorageActions, l as StripeActions, T as TwilioActions, W as WebhookActions, m as WikimediaActions, Y as YouTubeActions } from './contracts-Dv9PM_Cz.js';
4
- import { LogMeta } from '@almadar/core';
5
- export { I as IntegrationFactory, g as getIntegrationFactory, r as resetIntegrationFactory } from './factory-DTdVeyAi.js';
1
+ import { e as IntegrationLogger, c as IntegrationErrorCode, a as IntegrationConfig, B as BaseIntegration, d as IntegrationFactory, g as IntegrationParams, h as IntegrationResult, I as IntegrationCallContext } from './BaseIntegration-C_5q54DM.js';
2
+ export { b as IntegrationError, f as IntegrationParamValue, V as ValidationError, i as ValidationResult, j as getIntegrationFactory, r as resetIntegrationFactory, v as validateParams } from './BaseIntegration-C_5q54DM.js';
3
+ import { e as CredentialStore, d as CredentialPersistence, H as HookDeclaration } from './store-tehIm2rt.js';
4
+ export { A as ArxivActions, C as CLIActions, a as CREDENTIAL_ENTITY_TYPE, b as CREDENTIAL_MASTER_KEY_ENV, c as CredentialEntry, D as DatabaseActions, f as DatabaseDriver, g as DatabaseQueryParamValue, h as DatabaseQueryParams, i as DatabaseQueryResult, j as DatabaseRow, k as DeepAgentActions, l as DockerActions, E as EmailActions, G as GitHubActions, I as IconifyActions, m as IntegrationActionName, n as IntegrationContracts, o as IntegrationName, L as LLMIntegrationActions, M as MLActions, O as OAuthActions, p as OtelActions, Q as QueueActions, R as RedisActions, S as StorageActions, q as StripeActions, T as TwilioActions, W as WebhookActions, r as WikimediaActions, Y as YouTubeActions, s as serviceHooks } from './store-tehIm2rt.js';
5
+ import { LogMeta, EntityRow, EventPayload } from '@almadar/core';
6
6
  export { GitHubIntegration } from './integrations/github/index.js';
7
7
 
8
8
  /**
@@ -61,6 +61,55 @@ declare function isKnownIntegration(name: string): boolean;
61
61
  */
62
62
  declare function getRegisteredIntegrations(): string[];
63
63
 
64
+ /**
65
+ * The factory the host's `RuntimeIntegrationManager` configures — installed
66
+ * by its constructor so the `credentials.test` probe executes through the
67
+ * SAME factory (and therefore the same configs) as every other call-service.
68
+ */
69
+ declare function installActiveFactory(factory: IntegrationFactory): void;
70
+ declare function getActiveFactory(): IntegrationFactory | null;
71
+ /**
72
+ * Install the host's credential store as the process-wide resolution source.
73
+ * Called once at boot (playground / generated server) after the store is
74
+ * constructed over the host's persistence adapter.
75
+ */
76
+ declare function installCredentialStore(store: CredentialStore): void;
77
+ /** The installed store, for the credentials admin service. */
78
+ declare function getInstalledCredentialStore(): CredentialStore | null;
79
+ /** Testing/reset hook. */
80
+ declare function uninstallCredentialStore(): void;
81
+ /**
82
+ * The one credential-reference resolver: store → env → undefined.
83
+ * `ref` is an env-var name — the same name `serviceCredentials` declares and
84
+ * `connectionRef` params carry. Every place that used to read
85
+ * `process.env[ref]` for a credential routes through here.
86
+ */
87
+ declare function resolveCredentialRef(ref: string, env?: Record<string, string | undefined>): string | undefined;
88
+
89
+ /** Env var overriding where the dev credential file lives. */
90
+ declare const CREDENTIALS_FILE_ENV = "ALMADAR_CREDENTIALS_FILE";
91
+ /**
92
+ * File-backed `CredentialPersistence` for dev store-first mode (I-31): rows
93
+ * survive playground restarts so the encrypt-at-rest path is exercised on
94
+ * every dev run, exactly like a deployed app's Firestore-backed store. Rows
95
+ * arrive already encrypted (ciphertext/iv/authTag) — this adapter never sees
96
+ * plaintext. Writes are atomic (tmp file + rename). Never use in production.
97
+ */
98
+ declare class FileCredentialPersistence implements CredentialPersistence {
99
+ private readonly path;
100
+ private counter;
101
+ constructor(path?: string);
102
+ get filePath(): string;
103
+ private load;
104
+ private save;
105
+ create(entityType: string, data: EntityRow): Promise<{
106
+ id: string;
107
+ }>;
108
+ update(_entityType: string, id: string, data: EntityRow): Promise<void>;
109
+ delete(_entityType: string, id: string): Promise<void>;
110
+ list(_entityType: string): Promise<EntityRow[]>;
111
+ }
112
+
64
113
  /**
65
114
  * Canonical Almadar shapes for the Stripe integration.
66
115
  *
@@ -352,6 +401,219 @@ declare class WebhookIntegration extends BaseIntegration {
352
401
  private send;
353
402
  }
354
403
 
404
+ /**
405
+ * Web Push integration — VAPID-signed push notifications to browser
406
+ * PushSubscription endpoints. VAPID details are passed per call (never via the
407
+ * web-push module singleton) so concurrent configs cannot contaminate each other.
408
+ */
409
+ declare class PushIntegration extends BaseIntegration {
410
+ private vapidPublicKey;
411
+ private vapidPrivateKey;
412
+ private vapidSubject;
413
+ constructor(config: IntegrationConfig);
414
+ execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
415
+ private send;
416
+ }
417
+
418
+ /**
419
+ * Verify + parse Google Calendar push notifications (watch channels) into the
420
+ * canonical Almadar hook event. Google sends NO body — everything rides the
421
+ * `X-Goog-*` headers — and offers no HMAC; the only verifiable secret is the
422
+ * channel token we supplied at `calendar.watch` time, so pass `expectedToken`
423
+ * whenever the watch was registered with one.
424
+ *
425
+ * The googleapis SDK never appears here or in any route — this module is the
426
+ * whole provider surface, mirroring `stripe/webhooks.ts`.
427
+ */
428
+ type CalendarHookEvent = {
429
+ type: 'calendar.changed';
430
+ channelId: string;
431
+ resourceId: string;
432
+ /** `sync` (channel handshake), `exists`, or `not_exists`. */
433
+ resourceState: string;
434
+ messageNumber: number;
435
+ } | {
436
+ error: 'missing-headers';
437
+ } | {
438
+ error: 'bad-token';
439
+ };
440
+ declare function parseCalendarPushNotification(headers: Record<string, string | undefined>, expectedToken?: string): CalendarHookEvent;
441
+ /**
442
+ * Hook-provider adapter for the shared `/api/hooks/:provider` ingress: maps a
443
+ * Google Calendar push notification to the bus event `CAL_REMOTE_CHANGED`
444
+ * consumed by `std-calendar-sync`. The `sync` handshake message acknowledges
445
+ * without dispatching (it announces the channel, not a data change).
446
+ */
447
+ declare function googleCalendarHookProvider(expectedToken?: string): (input: {
448
+ headers: Record<string, string | undefined>;
449
+ rawBody: string;
450
+ }) => {
451
+ event: string;
452
+ payload: {
453
+ channelId: string;
454
+ resourceId: string;
455
+ resourceState: string;
456
+ };
457
+ } | {
458
+ error: string;
459
+ } | {
460
+ ack: true;
461
+ };
462
+
463
+ /**
464
+ * Google Calendar integration — service account auth, optionally acting as a
465
+ * Workspace user via domain-wide delegation (GOOGLE_CALENDAR_SUBJECT). All
466
+ * event times are ISO strings on the wire; a 10-char value (YYYY-MM-DD) maps
467
+ * to an all-day `date`, anything longer to `dateTime`.
468
+ */
469
+ declare class CalendarIntegration extends BaseIntegration {
470
+ private client;
471
+ private defaultCalendarId;
472
+ constructor(config: IntegrationConfig);
473
+ execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
474
+ private calendarId;
475
+ private toEventTime;
476
+ private fromEventTime;
477
+ private listEvents;
478
+ private resolveEnd;
479
+ private createEvent;
480
+ private updateEvent;
481
+ private deleteEvent;
482
+ private freeBusy;
483
+ private watch;
484
+ private stopWatch;
485
+ }
486
+
487
+ /**
488
+ * All registered inbound-hook providers, derived from the `serviceHooks`
489
+ * declarations (the single source the registry and codegen also derive from).
490
+ * Hosts that serve arbitrary schemas (the playground) mount this full map;
491
+ * generated apps get a per-app subset via the compiler's hooks-providers.ts.
492
+ *
493
+ * `HOOK_PROVIDER_FACTORIES` is the static factory table TypeScript needs
494
+ * (export names cannot be resolved dynamically without casts); the drift
495
+ * guard below fails loudly if a declaration names a factory this table lacks.
496
+ */
497
+
498
+ interface HookProviderInput {
499
+ headers: Record<string, string | undefined>;
500
+ rawBody: string;
501
+ }
502
+ type HookProviderResult = {
503
+ event: string;
504
+ payload: EventPayload;
505
+ } | {
506
+ ack: true;
507
+ } | {
508
+ error: string;
509
+ };
510
+ type RegisteredHookProvider = (input: HookProviderInput) => HookProviderResult;
511
+ /** Every hook declaration across all services — used by the drift-guard test. */
512
+ declare function allHookDeclarations(): HookDeclaration[];
513
+ /**
514
+ * Build the full provider map from every service's hook declarations,
515
+ * resolving each provider's verification secret from `env`. Throws when a
516
+ * declaration names a factory the table above does not carry — declaration
517
+ * and implementation must advance together.
518
+ */
519
+ declare function registeredHookProviders(env?: Record<string, string | undefined>): Record<string, RegisteredHookProvider>;
520
+
521
+ /**
522
+ * Google Drive integration — dual auth:
523
+ * - **Service account** (GOOGLE_DRIVE_SA_KEY, optional GOOGLE_DRIVE_SUBJECT
524
+ * delegation) serves reads (list/get/share).
525
+ * - **User OAuth** (GOOGLE_DRIVE_REFRESH_TOKEN + the app's OAUTH_CLIENT_ID/
526
+ * SECRET, obtained once via `tools/scripts/drive-consent.mjs`) serves
527
+ * WRITES (`uploadFile`/`createFolder`) when present — Google enforces zero
528
+ * SA storage quota on personal accounts, so SA writes into a shared My
529
+ * Drive folder are impossible; the user client also covers reads when no
530
+ * SA key is configured. `GOOGLE_DRIVE_FOLDER_ID` is the default upload
531
+ * parent. File content crosses this boundary as base64 (data URL accepted
532
+ * on upload).
533
+ */
534
+ declare class DriveIntegration extends BaseIntegration {
535
+ private readonly saClient;
536
+ private readonly userClient;
537
+ private readonly defaultFolderId;
538
+ constructor(config: IntegrationConfig);
539
+ /** Reads prefer the SA client (delegation-aware); user client covers its absence. */
540
+ private readClient;
541
+ /** Writes REQUIRE the user client on personal accounts (SA has no storage quota); SA only as a Workspace fallback. */
542
+ private writeClient;
543
+ execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
544
+ private listFiles;
545
+ private getFile;
546
+ private uploadFile;
547
+ private createFolder;
548
+ private shareFile;
549
+ }
550
+
551
+ /**
552
+ * Meta Ads integration — Graph API Marketing Insights, READ-ONLY (spend and
553
+ * campaign listings for profitability reporting). No SDK: plain fetch with
554
+ * the webhook integration's 5xx-retries / 4xx-returns split.
555
+ */
556
+ declare class MetaAdsIntegration extends BaseIntegration {
557
+ private accessToken;
558
+ private defaultAccountId;
559
+ constructor(config: IntegrationConfig);
560
+ execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
561
+ private accountId;
562
+ private graphGet;
563
+ private getSpend;
564
+ private listCampaigns;
565
+ }
566
+
567
+ /**
568
+ * Accounting export integration — the generic half of "export to accounting
569
+ * software": shapes invoice / journal rows into import-ready CSV without
570
+ * committing to a vendor. A `provider` field is reserved on the config for
571
+ * direct DATEV/Xero/QuickBooks connectors later; the CSV column sets follow
572
+ * the common import templates those systems accept.
573
+ */
574
+ declare class AccountingIntegration extends BaseIntegration {
575
+ constructor(config: IntegrationConfig);
576
+ execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
577
+ private exportRows;
578
+ }
579
+
580
+ /**
581
+ * Banking integration — GoCardless Bank Account Data (read-only requisition →
582
+ * accounts → transactions flow feeding reconciliation). Access tokens are
583
+ * minted per instance from the secret pair and refreshed on expiry.
584
+ */
585
+ declare class BankingIntegration extends BaseIntegration {
586
+ private secretId;
587
+ private secretKey;
588
+ private accessToken;
589
+ private accessTokenExpiresAt;
590
+ constructor(config: IntegrationConfig);
591
+ execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
592
+ private token;
593
+ private gcRequest;
594
+ private createRequisition;
595
+ private listAccounts;
596
+ private listTransactions;
597
+ }
598
+
599
+ /**
600
+ * E-signature integration — DocuSign eSignature REST first, deliberately
601
+ * provider-pluggable: the action surface (sendEnvelope / getEnvelopeStatus /
602
+ * downloadDocument) is vendor-neutral and every DocuSign shape stays inside
603
+ * this module. `DOCUSIGN_BASE_URL` carries the account-scoped REST base;
604
+ * `DOCUSIGN_ACCESS_TOKEN` the OAuth token (JWT-grant rotation is the
605
+ * deployment's concern — the token is read per call so a rotated env value
606
+ * takes effect without restart).
607
+ */
608
+ declare class EsignIntegration extends BaseIntegration {
609
+ constructor(config: IntegrationConfig);
610
+ execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
611
+ private dsRequest;
612
+ private sendEnvelope;
613
+ private getEnvelopeStatus;
614
+ private downloadDocument;
615
+ }
616
+
355
617
  /**
356
618
  * LLM integration using @almadar/llm
357
619
  *
@@ -502,24 +764,81 @@ declare class OtelIntegration extends BaseIntegration {
502
764
  private getAllMetrics;
503
765
  }
504
766
 
505
- /**
506
- * OAuth2/OIDC integration with in-memory mock backend.
767
+ /** Supported OAuth providers */
768
+ type OAuthProvider = 'google' | 'github' | 'auth0';
769
+ /** Server-held per-authorization state (never leaves the process). */
770
+ interface PendingAuthorization {
771
+ provider: OAuthProvider;
772
+ redirectUri: string;
773
+ pkceVerifier: string;
774
+ }
775
+ /**
776
+ * Where pending OIDC authorizations (PKCE verifier, redirect URI) live
777
+ * between `authorize` and `token`. The in-memory default works single-
778
+ * instance; a multi-instance deployment injects a shared-store impl (the
779
+ * FirestoreCredentialPersistence structural pattern) via
780
+ * `installPendingGrantStore` — no sticky routing needed once it does.
781
+ * `take` is single-use: it returns AND removes, so a state token can never
782
+ * be replayed. `sweep` drops expired grants.
783
+ */
784
+ interface PendingGrantStore {
785
+ put(state: string, grant: PendingAuthorization, ttlMs: number): Promise<void>;
786
+ take(state: string): Promise<PendingAuthorization | null>;
787
+ sweep(): Promise<void>;
788
+ }
789
+ declare class InMemoryPendingGrantStore implements PendingGrantStore {
790
+ private readonly grants;
791
+ put(state: string, grant: PendingAuthorization, ttlMs: number): Promise<void>;
792
+ take(state: string): Promise<PendingAuthorization | null>;
793
+ sweep(): Promise<void>;
794
+ }
795
+ /** Install a shared pending-grant store (multi-instance hosts); null resets to in-memory. */
796
+ declare function installPendingGrantStore(store: PendingGrantStore | null): void;
797
+ /**
798
+ * OAuth2/OIDC integration.
507
799
  *
508
- * This is a development/mock implementation. No actual OAuth library is used.
509
- * State tokens, access tokens, and refresh tokens are generated in-memory and
510
- * tracked via Maps. Useful for testing OAuth flows without external providers.
800
+ * Two backends behind one contract:
801
+ * - **OIDC (production)** `openid-client` against a discovered issuer
802
+ * (default Google; override via `OIDC_ISSUER_URL`), authorization-code +
803
+ * PKCE, real token exchange / refresh / revocation / userinfo. Selected
804
+ * whenever `OAUTH_CLIENT_ID` + `OAUTH_CLIENT_SECRET` are configured and
805
+ * `OAUTH_MODE` is not `mock`.
806
+ * - **Mock (dev/tests)** — the original in-memory backend, kept verbatim
807
+ * behind `OAUTH_MODE=mock` (or absent client credentials) so existing
808
+ * tests and offline dev flows are untouched.
809
+ *
810
+ * Pending-authorization state (PKCE verifier, redirect URI) lives in a
811
+ * `PendingGrantStore` — in-memory by default (single instance), injectable
812
+ * via `installPendingGrantStore` for multi-instance deployments (a shared
813
+ * store replaces the old sticky-routing requirement). Grants are TTL-bound
814
+ * and single-use.
511
815
  */
512
816
  declare class OAuthIntegration extends BaseIntegration {
513
- /** Maps state token -> provider for pending authorization flows */
817
+ /** Maps state token -> provider for pending MOCK authorization flows */
514
818
  private states;
515
- /** Maps access token -> token set */
819
+ /** Maps access token -> token set (mock backend) */
516
820
  private tokens;
517
- /** Maps refresh token -> access token for refresh lookups */
821
+ /** Maps refresh token -> access token for refresh lookups (mock backend) */
518
822
  private refreshIndex;
519
823
  /** Maps access token -> mock user session */
520
824
  private sessions;
825
+ /** Pending OIDC authorizations (real backend) — injectable, in-memory default. */
826
+ private readonly fallbackPending;
827
+ private pendingStore;
828
+ /** Maps access token -> ID-token subject, for userinfo subject checks */
829
+ private subjects;
830
+ /** Discovered issuer configurations, keyed by issuer URL */
831
+ private discovered;
832
+ private readonly real;
521
833
  constructor(config: IntegrationConfig);
522
834
  execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
835
+ private issuerFor;
836
+ private configurationFor;
837
+ private oidcAuthorize;
838
+ private oidcToken;
839
+ private oidcRefresh;
840
+ private oidcRevoke;
841
+ private oidcUserinfo;
523
842
  /** Generate a random hex token of the given byte length. */
524
843
  private generateToken;
525
844
  /** Generate a mock user profile from a provider and access token. */
@@ -532,26 +851,62 @@ declare class OAuthIntegration extends BaseIntegration {
532
851
  }
533
852
 
534
853
  /**
535
- * Storage integration with in-memory backend for development/testing.
854
+ * The hosted credential store's service surface (W4 Tier C) — what the
855
+ * Owner-gated Integrations settings page calls through the NORMAL
856
+ * call-service path (server-side only; organisms own the access policy,
857
+ * per the I-16 std-atom ACL constraint).
858
+ *
859
+ * Security contract: `list` returns masked entries only (last-4, never
860
+ * plaintext); `set` accepts only env vars DECLARED in `serviceCredentials`
861
+ * for the named service (plus well-formed connection refs for `database`),
862
+ * so the page can never become an arbitrary env-injection surface; values
863
+ * are never logged. `set`/`remove`/`test` additionally require the caller's
864
+ * role (from IntegrationCallContext) to be in the admin list
865
+ * (ALMADAR_CREDENTIAL_ADMIN_ROLES, default admin,owner) and FAIL CLOSED
866
+ * without one — the un-bypassable twin of the organism-side page gate (I-25).
867
+ */
868
+ declare class CredentialsIntegration extends BaseIntegration {
869
+ constructor(config: IntegrationConfig);
870
+ execute(action: string, params: IntegrationParams, context?: IntegrationCallContext): Promise<IntegrationResult>;
871
+ private adminRoles;
872
+ private declaredFor;
873
+ private assertSettable;
874
+ private storeFirst;
875
+ private list;
876
+ private set;
877
+ private remove;
878
+ private test;
879
+ }
880
+
881
+ /**
882
+ * Object storage integration — real S3-compatible backend (AWS S3, R2, MinIO,
883
+ * …) when `STORAGE_ACCESS_KEY_ID`/`STORAGE_SECRET_ACCESS_KEY` are configured,
884
+ * in-memory simulation otherwise. Production REFUSES the in-memory fallback:
885
+ * a missing credential must fail loudly, never simulate success (D-3).
536
886
  *
537
- * Provides S3-compatible object storage operations (upload, download, list,
538
- * delete, getSignedUrl) backed by an in-memory Map. No cloud SDK dependencies
539
- * are required.
887
+ * `upload` admits two shapes: the canonical `{ key, content }` pair and the
888
+ * file-form `{ file: { name, size, type, content }, acl?, maxSize? }` that
889
+ * lolo authors wire from UploadDropZone. The result carries `id`/`url`
890
+ * alongside `key` — the fields the .lolo consumers read.
540
891
  */
541
892
  declare class StorageIntegration extends BaseIntegration {
542
893
  private objects;
894
+ private s3;
895
+ private defaultBucket;
896
+ private publicUrlBase;
543
897
  constructor(config: IntegrationConfig);
544
898
  execute(action: string, params: IntegrationParams): Promise<IntegrationResult>;
545
- /** Build a composite key from bucket and object key. */
899
+ private bucketOf;
546
900
  private compositeKey;
547
- /** Generate a deterministic etag from content. */
548
901
  private generateEtag;
549
- /** Compute the byte size of content. */
550
- private computeSize;
902
+ /** Resolve the upload inputs from either admitted shape. */
903
+ private resolveUpload;
904
+ private publicUrl;
551
905
  private upload;
552
906
  private download;
553
907
  private list;
554
908
  private deleteObject;
909
+ private signUrl;
555
910
  private getSignedUrl;
556
911
  }
557
912
 
@@ -658,4 +1013,4 @@ declare class ArxivIntegration extends BaseIntegration {
658
1013
  private search;
659
1014
  }
660
1015
 
661
- export { type AlmadarCheckoutSession, type AlmadarCustomer, type AlmadarInvoiceFailure, type AlmadarInvoicePayment, type AlmadarPortalSession, type AlmadarStripeEvent, type AlmadarStripeEventOk, type AlmadarSubscription, type AlmadarSubscriptionStatus, type AlmadarTier, ArxivIntegration, type ArxivResult, BaseIntegration, CLIIntegration, type CancelSubscriptionInput, ConsoleLogger, type CreateCheckoutInput, type CreateCustomerInput, type CreatePortalInput, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, EmailIntegration, IconifyIntegration, IntegrationConfig, type IntegrationConstructor, IntegrationErrorCode, IntegrationLogger, IntegrationParams, IntegrationResult, LLMIntegration, MLIntegration, OAuthIntegration, OtelIntegration, QueueIntegration, RedisIntegration, type RetryConfig, type SqlGuardResult, StorageIntegration, StripeIntegration, type StripePriceMap, TwilioIntegration, type UpdateSubscriptionInput, type VerifyAndParseInput, WebhookIntegration, WikimediaIntegration, YouTubeIntegration, assertReadOnlySelect, getIntegration, getRegisteredIntegrations, isKnownIntegration, registerIntegration, verifyAndParseStripeEvent, withRetry };
1016
+ export { AccountingIntegration, type AlmadarCheckoutSession, type AlmadarCustomer, type AlmadarInvoiceFailure, type AlmadarInvoicePayment, type AlmadarPortalSession, type AlmadarStripeEvent, type AlmadarStripeEventOk, type AlmadarSubscription, type AlmadarSubscriptionStatus, type AlmadarTier, ArxivIntegration, type ArxivResult, BankingIntegration, BaseIntegration, CLIIntegration, CREDENTIALS_FILE_ENV, CalendarIntegration, type CancelSubscriptionInput, ConsoleLogger, type CreateCheckoutInput, type CreateCustomerInput, type CreatePortalInput, CredentialPersistence, CredentialStore, CredentialsIntegration, DatabaseIntegration, DeepAgentIntegration, DockerIntegration, DriveIntegration, EmailIntegration, EsignIntegration, FileCredentialPersistence, HookDeclaration, type HookProviderInput, type HookProviderResult, IconifyIntegration, InMemoryPendingGrantStore, IntegrationCallContext, IntegrationConfig, type IntegrationConstructor, IntegrationErrorCode, IntegrationFactory, IntegrationLogger, IntegrationParams, IntegrationResult, LLMIntegration, MLIntegration, MetaAdsIntegration, OAuthIntegration, OtelIntegration, type PendingGrantStore, PushIntegration, QueueIntegration, RedisIntegration, type RegisteredHookProvider, type RetryConfig, type SqlGuardResult, StorageIntegration, StripeIntegration, type StripePriceMap, TwilioIntegration, type UpdateSubscriptionInput, type VerifyAndParseInput, WebhookIntegration, WikimediaIntegration, YouTubeIntegration, allHookDeclarations, assertReadOnlySelect, getActiveFactory, getInstalledCredentialStore, getIntegration, getRegisteredIntegrations, googleCalendarHookProvider, installActiveFactory, installCredentialStore, installPendingGrantStore, isKnownIntegration, parseCalendarPushNotification, registerIntegration, registeredHookProviders, resolveCredentialRef, uninstallCredentialStore, verifyAndParseStripeEvent, withRetry };