couchset 0.4.1 → 0.5.1

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.
Files changed (39) hide show
  1. package/README.md +177 -2
  2. package/dist/database.d.ts +6 -0
  3. package/dist/database.js +51 -2
  4. package/dist/database.js.map +1 -1
  5. package/dist/eventing.d.ts +179 -0
  6. package/dist/eventing.js +822 -0
  7. package/dist/eventing.js.map +1 -0
  8. package/dist/model/include.d.ts +36 -3
  9. package/dist/model/include.js +154 -49
  10. package/dist/model/include.js.map +1 -1
  11. package/dist/model/index.d.ts +4 -1
  12. package/dist/model/index.js +8 -1
  13. package/dist/model/index.js.map +1 -1
  14. package/dist/model/read-helpers.d.ts +6 -2
  15. package/dist/model/read-helpers.js +96 -23
  16. package/dist/model/read-helpers.js.map +1 -1
  17. package/dist/model/read-types.d.ts +51 -0
  18. package/dist/model/read-types.js +3 -0
  19. package/dist/model/read-types.js.map +1 -0
  20. package/dist/model/safe-query.d.ts +3 -0
  21. package/dist/model/safe-query.js +22 -2
  22. package/dist/model/safe-query.js.map +1 -1
  23. package/dist/next.d.ts +20 -2
  24. package/dist/next.js +26 -1
  25. package/dist/next.js.map +1 -1
  26. package/dist/next.types.js +149 -1
  27. package/dist/next.types.js.map +1 -1
  28. package/dist/pagination/pagination.js +3 -1
  29. package/dist/pagination/pagination.js.map +1 -1
  30. package/dist/pagination/types.d.ts +2 -0
  31. package/dist/pagination/types.js.map +1 -1
  32. package/dist/search/customQuery.d.ts +2 -0
  33. package/dist/search/customQuery.js +4 -1
  34. package/dist/search/customQuery.js.map +1 -1
  35. package/docs/beta-migration.md +1 -1
  36. package/docs/document-modeling.md +5 -1
  37. package/docs/joins-and-consistency.md +228 -0
  38. package/docs/next-primitives.md +37 -0
  39. package/package.json +2 -1
package/README.md CHANGED
@@ -10,15 +10,17 @@
10
10
 
11
11
  CouchSet is a Couchbase model layer for TypeScript and Node.js. The default `couchset` entrypoint keeps the legacy API for safe upgrades; the modern API is available from `couchset/next`.
12
12
 
13
- The additive client-owned primitives—typed definitions, explicit provisioning, transaction-bound models, CAS helpers, and safe index plans—are documented in [Next primitives](./docs/next-primitives.md).
13
+ The additive client-owned primitives—typed definitions, explicit provisioning, transaction-bound models, CAS helpers, safe index plans, and Eventing—are summarized below. Their complete operational guide is [Next primitives](./docs/next-primitives.md).
14
14
 
15
15
  - [Install](#install)
16
16
  - [Legacy Default](#legacy-default)
17
17
  - [Modern API](#modern-api)
18
+ - [Modern Client Primitives](#modern-client-primitives)
18
19
  - [Next primitives](./docs/next-primitives.md)
19
20
  - [Connection Lifecycle](#connection-lifecycle)
20
21
  - [Models](#models)
21
22
  - [Reads](#reads)
23
+ - [Typed Joins and Read Consistency](#typed-joins-and-read-consistency)
22
24
  - [Document Modeling](./docs/document-modeling.md)
23
25
  - [Writes](#writes)
24
26
  - [Queries](#queries)
@@ -113,6 +115,88 @@ const page = await users.page<User>({
113
115
  await users.deleteById(created.id, {hard: true});
114
116
  ```
115
117
 
118
+ ## Modern Client Primitives
119
+
120
+ `couchset/next` also offers a client-owned API for typed manifests, explicit administrative work, safe operational plans, and Eventing. These are deliberately separate from the singleton `Model` API above.
121
+
122
+ ### Declarative models
123
+
124
+ ```ts
125
+ import {createCouchsetClient, defineModel} from 'couchset/next';
126
+
127
+ const sessions = defineModel({name: 'Session', scope: 'auth', collection: 'sessions'});
128
+ const db = createCouchsetClient({bucketName: 'app', models: [sessions]});
129
+ const sessionModel = db.model(sessions); // registers and binds; no DDL
130
+ ```
131
+
132
+ Read the [full client and model-definition guide](./docs/next-primitives.md#couchset-next-primitives).
133
+
134
+ ### Provisioning and dynamic models
135
+
136
+ ```ts
137
+ await db.ensureCollections(); // creates only missing scopes and collections
138
+ await db.ensureIndexes(); // create-only index DDL
139
+
140
+ const reports = await db.registerModel(reportDefinition, {provision: {collections: true}});
141
+ ```
142
+
143
+ Read about [provisioning and dynamic models](./docs/next-primitives.md#provisioning-and-dynamic-models).
144
+
145
+ ### Transactions and CAS
146
+
147
+ ```ts
148
+ await db.transaction(async (tx) => {
149
+ await tx.model(sessions).insert({id: 'session::1', userId: 'user::1'});
150
+ });
151
+
152
+ const outcome = await sessionModel.consumeOnce('session::1', knownCas);
153
+ ```
154
+
155
+ Read the [transaction and CAS safety notes](./docs/next-primitives.md#transactions-and-cas).
156
+
157
+ ### Safe index plans
158
+
159
+ ```ts
160
+ const plan = await db.planIndexes(); // inspect missing, matching, and drifted indexes
161
+ await db.applyIndexPlan(plan); // creates safe replacements and waits for them
162
+ ```
163
+
164
+ Read about [index drift and opt-in cleanup](./docs/next-primitives.md#index-drift).
165
+
166
+ ### Eventing functions
167
+
168
+ ```ts
169
+ import {defineEventingFunction} from 'couchset/next';
170
+
171
+ const auditOrders = defineEventingFunction({
172
+ name: 'audit_orders',
173
+ code: 'function OnUpdate(doc, meta) { log(meta.id); }',
174
+ sourceKeyspace: {bucket: 'app', scope: 'sales', collection: 'orders'},
175
+ });
176
+
177
+ const eventing = db.eventing({
178
+ namespace: 'billing',
179
+ metadataKeyspace: {bucket: 'app', scope: 'eventing', collection: 'billing_metadata'},
180
+ definitions: [auditOrders],
181
+ });
182
+
183
+ await eventing.apply();
184
+ ```
185
+
186
+ Read the [Eventing lifecycle and safety guide](./docs/next-primitives.md#eventing-functions).
187
+
188
+ ### Test fixtures
189
+
190
+ ```ts
191
+ import {createCouchsetTestFixture} from 'couchset/next';
192
+
193
+ const {model, cleanup} = await createCouchsetTestFixture(db, {name: 'Invoice'});
194
+ // use model in the test
195
+ await cleanup();
196
+ ```
197
+
198
+ Read about [isolated CouchSet test fixtures](./docs/next-primitives.md#tests).
199
+
116
200
  ## Connection Lifecycle
117
201
 
118
202
  Models can be declared before connecting. Model operations wait for the shared connection before binding to the Couchbase bucket and collection.
@@ -150,7 +234,15 @@ await startCouchbase();
150
234
  await startCouchbaseServerless();
151
235
  ```
152
236
 
153
- The starters read `COUCHBASE_URL`, `COUCHBASE_BUCKET`, `COUCHBASE_USERNAME`, `COUCHBASE_PASSWORD`, and `COUCHBASE_PROXY`. You can pass any `CouchsetArgs` field as an override.
237
+ The starters accept one PostgreSQL-style `DB_URL` in place of the four connection settings. It takes precedence over `COUCHBASE_URL`, `COUCHBASE_BUCKET`, `COUCHBASE_USERNAME`, and `COUCHBASE_PASSWORD`; explicit `startCouchbase({...})` options still take precedence over either environment form.
238
+
239
+ ```bash
240
+ DB_URL=couchbase://user:password@localhost/bucket
241
+ DB_URL=couchbase://user:password@localhost:11210/bucket
242
+ DB_URL=couchbases://user:password@cb.example.com/bucket
243
+ ```
244
+
245
+ Use `couchbases://` for TLS. Percent-encode reserved characters in usernames, passwords, and bucket names (for example, `p%40ss` for `p@ss`). `COUCHBASE_PROXY` remains available as a separate optional setting.
154
246
 
155
247
  ## Models
156
248
 
@@ -230,6 +322,89 @@ await users.onlyDeleted().findMany<User>();
230
322
  await users.withoutDefaultWhere().findMany<User>();
231
323
  ```
232
324
 
325
+ ## Typed Joins and Read Consistency
326
+
327
+ Client-bound models infer root and related fields. Using the client-owned `db`
328
+ above, join profiles to battles by arbitrary fields:
329
+
330
+ ```ts
331
+ import {dateCodec, defineModel, joinField} from 'couchset/next';
332
+ import {QueryScanConsistency} from 'couchbase';
333
+
334
+ const battles = db.model(defineModel<{
335
+ createdByUserId: string;
336
+ startsAt: Date;
337
+ }>({name: 'Battle', scope: 'app', collection: 'battles', codecs: {startsAt: dateCodec}}));
338
+
339
+ const profiles = db.model(defineModel<{
340
+ ownerUserId: string;
341
+ displayName: string;
342
+ birthday: Date;
343
+ }>({name: 'Profile', scope: 'app', collection: 'profiles', codecs: {birthday: dateCodec}}));
344
+
345
+ const joined = await battles.page({
346
+ sourceAlias: 'battle',
347
+ include: [{
348
+ as: 'creator',
349
+ model: profiles,
350
+ type: 'leftJoin',
351
+ on: {
352
+ left: joinField('creator.ownerUserId'),
353
+ op: '$eq',
354
+ right: joinField('battle.createdByUserId'),
355
+ },
356
+ }],
357
+ limit: 20,
358
+ queryOptions: {scanConsistency: QueryScanConsistency.RequestPlus},
359
+ });
360
+
361
+ joined.items[0]?.startsAt; // Date | undefined
362
+ joined.items[0]?.creator?.birthday; // Date | undefined; related codec applied
363
+ ```
364
+
365
+ Provision the collections and appropriate indexes explicitly before querying.
366
+ `joinField()` denotes a field reference; an ordinary string is a bound value.
367
+ Use `$and` / `$or` to combine predicates. Existing `key` / `keys` includes still
368
+ use `ON KEYS`.
369
+
370
+ Use NEST for arrays, and select just the fields needed:
371
+
372
+ ```ts
373
+ const summaries = await battles.findMany({
374
+ select: ['startsAt'],
375
+ include: [{
376
+ as: 'creators',
377
+ model: profiles,
378
+ type: 'leftNest',
379
+ on: {left: joinField('creators.ownerUserId'), op: '$eq', right: joinField('doc.createdByUserId')},
380
+ select: ['displayName', 'birthday'],
381
+ }],
382
+ });
383
+ // {startsAt: Date; creators: {displayName: string; birthday: Date}[]}[]
384
+ ```
385
+
386
+ LEFT JOIN may omit its related property; LEFT NEST returns `[]` when unmatched.
387
+ JOIN preserves one row per match, including repeated root IDs. Choose an alias
388
+ that does not overwrite a root field. NEST does not promise source-key ordering.
389
+
390
+ For read-your-writes, pass tokens from successful SDK mutations:
391
+
392
+ ```ts
393
+ import {MutationState, MutationToken} from 'couchbase';
394
+
395
+ async function readAfterWrites(tokens: MutationToken[]) {
396
+ return battles.findMany({
397
+ queryOptions: {consistentWith: new MutationState(...tokens)},
398
+ });
399
+ }
400
+ // Call with SDK mutationResult.token values, not whole mutation results.
401
+ ```
402
+
403
+ `request_plus` and `consistentWith` are alternatives; neither is a multi-document
404
+ transaction. Defaults are unchanged when no consistency option is supplied.
405
+ See [joined reads and consistency](./docs/joins-and-consistency.md) for predicates,
406
+ projection limits, codecs, compatibility changes, and live validation results.
407
+
233
408
  ## Writes
234
409
 
235
410
  ```ts
@@ -3,6 +3,12 @@ export type CouchbaseStarterLogger = ((...args: any[]) => void) | false;
3
3
  export interface StartCouchbaseOptions extends Partial<CouchsetArgs> {
4
4
  logger?: CouchbaseStarterLogger;
5
5
  }
6
+ /**
7
+ * Convert a PostgreSQL-style DB_URL into Couchbase SDK connection settings.
8
+ * The bucket lives in the URL path; it is not part of Couchbase's connection
9
+ * string, which contains only the scheme, host, optional port, and options.
10
+ */
11
+ export declare const parseDatabaseUrl: (value: string) => Pick<CouchsetArgs, "bucketName" | "connectionString" | "password" | "username">;
6
12
  export declare const getConnectionOptions: (overrides?: Partial<CouchsetArgs>) => CouchsetArgs;
7
13
  export declare const connectionOptions: CouchsetArgs;
8
14
  export declare const startCouchbase: (options?: StartCouchbaseOptions) => Promise<boolean>;
package/dist/database.js CHANGED
@@ -86,13 +86,61 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
86
86
  return (mod && mod.__esModule) ? mod : { "default": mod };
87
87
  };
88
88
  Object.defineProperty(exports, "__esModule", { value: true });
89
- exports.startCouchbaseServerless = exports.startCouchbase = exports.connectionOptions = exports.getConnectionOptions = void 0;
89
+ exports.startCouchbaseServerless = exports.startCouchbase = exports.connectionOptions = exports.getConnectionOptions = exports.parseDatabaseUrl = void 0;
90
90
  var connection_1 = __importDefault(require("./connection"));
91
91
  var envValue = function (key, fallback) {
92
92
  if (fallback === void 0) { fallback = ''; }
93
93
  var value = typeof process !== 'undefined' && process.env ? process.env[key] : undefined;
94
94
  return value === undefined ? fallback : value;
95
95
  };
96
+ var databaseUrlError = function (reason) {
97
+ return new Error("DB_URL must use couchbase:// or couchbases://user:password@host/bucket: ".concat(reason));
98
+ };
99
+ var decodeDatabaseUrlComponent = function (value, label) {
100
+ try {
101
+ return decodeURIComponent(value);
102
+ }
103
+ catch (_error) {
104
+ throw databaseUrlError("".concat(label, " contains invalid percent-encoding"));
105
+ }
106
+ };
107
+ /**
108
+ * Convert a PostgreSQL-style DB_URL into Couchbase SDK connection settings.
109
+ * The bucket lives in the URL path; it is not part of Couchbase's connection
110
+ * string, which contains only the scheme, host, optional port, and options.
111
+ */
112
+ var parseDatabaseUrl = function (value) {
113
+ var url;
114
+ try {
115
+ url = new URL(value);
116
+ }
117
+ catch (_error) {
118
+ throw databaseUrlError('the value is not a valid URL');
119
+ }
120
+ if (url.protocol !== 'couchbase:' && url.protocol !== 'couchbases:') {
121
+ throw databaseUrlError("unsupported protocol ".concat(url.protocol || '(missing)'));
122
+ }
123
+ if (!url.hostname) {
124
+ throw databaseUrlError('a host is required');
125
+ }
126
+ if (!url.username || !url.password) {
127
+ throw databaseUrlError('a username and password are required');
128
+ }
129
+ if (url.hash) {
130
+ throw databaseUrlError('fragments are not supported');
131
+ }
132
+ var bucketName = decodeDatabaseUrlComponent(url.pathname.replace(/^\//, ''), 'the bucket name');
133
+ if (!bucketName || bucketName.indexOf('/') !== -1) {
134
+ throw databaseUrlError('the path must contain exactly one bucket name');
135
+ }
136
+ return {
137
+ bucketName: bucketName,
138
+ connectionString: "".concat(url.protocol, "//").concat(url.host).concat(url.search),
139
+ password: decodeDatabaseUrlComponent(url.password, 'the password'),
140
+ username: decodeDatabaseUrlComponent(url.username, 'the username'),
141
+ };
142
+ };
143
+ exports.parseDatabaseUrl = parseDatabaseUrl;
96
144
  var maskPassword = function (password) {
97
145
  return password ? 'xxxxxx' : 'empty';
98
146
  };
@@ -104,6 +152,7 @@ var splitStartOptions = function (options) {
104
152
  var getConnectionOptions = function (overrides) {
105
153
  if (overrides === void 0) { overrides = {}; }
106
154
  var proxy = envValue('COUCHBASE_PROXY');
155
+ var databaseUrl = envValue('DB_URL');
107
156
  var options = {
108
157
  bucketName: envValue('COUCHBASE_BUCKET', 'dev'),
109
158
  connectionString: envValue('COUCHBASE_URL', 'couchbase://localhost'),
@@ -113,7 +162,7 @@ var getConnectionOptions = function (overrides) {
113
162
  if (proxy) {
114
163
  options.proxy = proxy;
115
164
  }
116
- return __assign(__assign({}, options), overrides);
165
+ return __assign(__assign(__assign({}, options), (databaseUrl ? (0, exports.parseDatabaseUrl)(databaseUrl) : {})), overrides);
117
166
  };
118
167
  exports.getConnectionOptions = getConnectionOptions;
119
168
  exports.connectionOptions = (0, exports.getConnectionOptions)();
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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","sourcesContent":["import CouchbaseConnection, {CouchsetArgs} from './connection';\n\nexport type CouchbaseStarterLogger = ((...args: any[]) => void) | false;\n\nexport interface StartCouchbaseOptions extends Partial<CouchsetArgs> {\n logger?: CouchbaseStarterLogger;\n}\n\nconst envValue = (key: string, fallback = ''): string => {\n const value = typeof process !== 'undefined' && process.env ? process.env[key] : undefined;\n\n return value === undefined ? fallback : value;\n};\n\nconst maskPassword = (password: string): string => {\n return password ? 'xxxxxx' : 'empty';\n};\n\nconst splitStartOptions = (options: StartCouchbaseOptions = {}) => {\n const {logger, ...connectionOverrides} = options;\n\n return {connectionOverrides, logger};\n};\n\nexport const getConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const proxy = envValue('COUCHBASE_PROXY');\n const options: CouchsetArgs = {\n bucketName: envValue('COUCHBASE_BUCKET', 'dev'),\n connectionString: envValue('COUCHBASE_URL', 'couchbase://localhost'),\n password: envValue('COUCHBASE_PASSWORD', '1234'),\n username: envValue('COUCHBASE_USERNAME', 'admin'),\n };\n\n if (proxy) {\n options.proxy = proxy;\n }\n\n return {\n ...options,\n ...overrides,\n };\n};\n\nexport const connectionOptions: CouchsetArgs = getConnectionOptions();\n\nconst refreshConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const nextOptions = getConnectionOptions(overrides);\n\n Object.keys(connectionOptions).forEach((key) => {\n delete (connectionOptions as any)[key];\n });\n Object.assign(connectionOptions, nextOptions);\n\n return connectionOptions;\n};\n\nconst logConnectionStart = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'starting',\n mode,\n JSON.stringify({\n bucket: options.bucketName,\n host: options.connectionString,\n password: maskPassword(options.password),\n username: options.username,\n })\n );\n};\n\nconst logConnectionStarted = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'started',\n mode,\n JSON.stringify({bucket: options.bucketName, host: options.connectionString})\n );\n};\n\nexport const startCouchbase = async (options: StartCouchbaseOptions = {}): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'standard');\n await CouchbaseConnection.Instance.init(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'standard');\n\n return true;\n};\n\nexport const startCouchbaseServerless = async (\n options: StartCouchbaseOptions = {}\n): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'serverless');\n await CouchbaseConnection.Instance.initServerless(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'serverless');\n\n return true;\n};\n"]}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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","sourcesContent":["import CouchbaseConnection, {CouchsetArgs} from './connection';\n\nexport type CouchbaseStarterLogger = ((...args: any[]) => void) | false;\n\nexport interface StartCouchbaseOptions extends Partial<CouchsetArgs> {\n logger?: CouchbaseStarterLogger;\n}\n\nconst envValue = (key: string, fallback = ''): string => {\n const value = typeof process !== 'undefined' && process.env ? process.env[key] : undefined;\n\n return value === undefined ? fallback : value;\n};\n\nconst databaseUrlError = (reason: string): Error =>\n new Error(`DB_URL must use couchbase:// or couchbases://user:password@host/bucket: ${reason}`);\n\nconst decodeDatabaseUrlComponent = (value: string, label: string): string => {\n try {\n return decodeURIComponent(value);\n } catch (_error) {\n throw databaseUrlError(`${label} contains invalid percent-encoding`);\n }\n};\n\n/**\n * Convert a PostgreSQL-style DB_URL into Couchbase SDK connection settings.\n * The bucket lives in the URL path; it is not part of Couchbase's connection\n * string, which contains only the scheme, host, optional port, and options.\n */\nexport const parseDatabaseUrl = (\n value: string\n): Pick<CouchsetArgs, 'bucketName' | 'connectionString' | 'password' | 'username'> => {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch (_error) {\n throw databaseUrlError('the value is not a valid URL');\n }\n\n if (url.protocol !== 'couchbase:' && url.protocol !== 'couchbases:') {\n throw databaseUrlError(`unsupported protocol ${url.protocol || '(missing)'}`);\n }\n if (!url.hostname) {\n throw databaseUrlError('a host is required');\n }\n if (!url.username || !url.password) {\n throw databaseUrlError('a username and password are required');\n }\n if (url.hash) {\n throw databaseUrlError('fragments are not supported');\n }\n\n const bucketName = decodeDatabaseUrlComponent(\n url.pathname.replace(/^\\//, ''),\n 'the bucket name'\n );\n if (!bucketName || bucketName.indexOf('/') !== -1) {\n throw databaseUrlError('the path must contain exactly one bucket name');\n }\n\n return {\n bucketName,\n connectionString: `${url.protocol}//${url.host}${url.search}`,\n password: decodeDatabaseUrlComponent(url.password, 'the password'),\n username: decodeDatabaseUrlComponent(url.username, 'the username'),\n };\n};\n\nconst maskPassword = (password: string): string => {\n return password ? 'xxxxxx' : 'empty';\n};\n\nconst splitStartOptions = (options: StartCouchbaseOptions = {}) => {\n const {logger, ...connectionOverrides} = options;\n\n return {connectionOverrides, logger};\n};\n\nexport const getConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const proxy = envValue('COUCHBASE_PROXY');\n const databaseUrl = envValue('DB_URL');\n const options: CouchsetArgs = {\n bucketName: envValue('COUCHBASE_BUCKET', 'dev'),\n connectionString: envValue('COUCHBASE_URL', 'couchbase://localhost'),\n password: envValue('COUCHBASE_PASSWORD', '1234'),\n username: envValue('COUCHBASE_USERNAME', 'admin'),\n };\n\n if (proxy) {\n options.proxy = proxy;\n }\n\n return {\n ...options,\n ...(databaseUrl ? parseDatabaseUrl(databaseUrl) : {}),\n ...overrides,\n };\n};\n\nexport const connectionOptions: CouchsetArgs = getConnectionOptions();\n\nconst refreshConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const nextOptions = getConnectionOptions(overrides);\n\n Object.keys(connectionOptions).forEach((key) => {\n delete (connectionOptions as any)[key];\n });\n Object.assign(connectionOptions, nextOptions);\n\n return connectionOptions;\n};\n\nconst logConnectionStart = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'starting',\n mode,\n JSON.stringify({\n bucket: options.bucketName,\n host: options.connectionString,\n password: maskPassword(options.password),\n username: options.username,\n })\n );\n};\n\nconst logConnectionStarted = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'started',\n mode,\n JSON.stringify({bucket: options.bucketName, host: options.connectionString})\n );\n};\n\nexport const startCouchbase = async (options: StartCouchbaseOptions = {}): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'standard');\n await CouchbaseConnection.Instance.init(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'standard');\n\n return true;\n};\n\nexport const startCouchbaseServerless = async (\n options: StartCouchbaseOptions = {}\n): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'serverless');\n await CouchbaseConnection.Instance.initServerless(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'serverless');\n\n return true;\n};\n"]}
@@ -0,0 +1,179 @@
1
+ import type { EventingFunction, EventingFunctionManager, EventingFunctionSettings, EventingFunctionState } from 'couchbase';
2
+ /** A Couchbase bucket/scope/collection used by an Eventing function. */
3
+ export interface EventingKeyspace {
4
+ bucket: string;
5
+ scope?: string;
6
+ collection?: string;
7
+ }
8
+ /**
9
+ * A declarative Eventing handler. `name` is logical: CouchSet derives the
10
+ * physical Couchbase name from the Eventing namespace.
11
+ */
12
+ export interface EventingDefinition {
13
+ name: string;
14
+ code: string;
15
+ sourceKeyspace: EventingKeyspace;
16
+ enforceSchema?: boolean;
17
+ bucketBindings?: EventingFunction['bucketBindings'];
18
+ urlBindings?: EventingFunction['urlBindings'];
19
+ constantBindings?: EventingFunction['constantBindings'];
20
+ settings?: Partial<EventingFunctionSettings>;
21
+ }
22
+ export type EventingFunctionDefinition = EventingDefinition;
23
+ /**
24
+ * The metadata collection is used only by Couchbase Eventing for checkpoints
25
+ * and timers. CouchSet never opens it as an application collection or writes
26
+ * documents to it.
27
+ */
28
+ export interface EventingOptions {
29
+ /** Required ownership boundary for physical Couchbase function names. */
30
+ namespace: string;
31
+ /** A dedicated collection reserved for Couchbase Eventing metadata. */
32
+ metadataKeyspace: EventingKeyspace;
33
+ /** Definitions registered when the control plane is constructed. */
34
+ definitions?: EventingDefinition[];
35
+ /** Alias for definitions, useful for manifest-shaped configuration. */
36
+ functions?: EventingDefinition[];
37
+ /** Explicit SDK manager injection, primarily for tests or owned clusters. */
38
+ manager?: EventingFunctionManagerLike;
39
+ /** Maximum time to wait for Couchbase Eventing lifecycle convergence. */
40
+ lifecycleTimeoutMs?: number;
41
+ /** Delay between lifecycle status checks. Defaults to 250ms. */
42
+ lifecyclePollIntervalMs?: number;
43
+ }
44
+ export interface EventingApplyOptions {
45
+ /**
46
+ * Permit source or metadata keyspace changes. Couchbase must undeploy first,
47
+ * which erases the function's timers and checkpoints.
48
+ */
49
+ allowRecreate?: boolean;
50
+ }
51
+ export type EventingOutcomeAction = 'created' | 'updated' | 'resumed' | 'unchanged' | 'pruned' | 'paused' | 'removed' | 'requires-recreate';
52
+ export interface EventingOutcome {
53
+ action: EventingOutcomeAction;
54
+ /** Lifecycle operations performed for this function, in order. */
55
+ actions: EventingOutcomeAction[];
56
+ name: string;
57
+ physicalName: string;
58
+ /** Present whenever undeploying can erase Eventing timers/checkpoints. */
59
+ timerStateLost?: boolean;
60
+ message?: string;
61
+ }
62
+ /**
63
+ * Each status array contains the matching outcome, so callers can inspect a
64
+ * report directly without parsing text. An update can also be in `paused` and
65
+ * `resumed`, because that is the safe lifecycle used to perform the update.
66
+ */
67
+ export interface EventingReport {
68
+ outcomes: EventingOutcome[];
69
+ created: EventingOutcome[];
70
+ updated: EventingOutcome[];
71
+ resumed: EventingOutcome[];
72
+ unchanged: EventingOutcome[];
73
+ pruned: EventingOutcome[];
74
+ paused: EventingOutcome[];
75
+ removed: EventingOutcome[];
76
+ requiresRecreate: EventingOutcome[];
77
+ }
78
+ /** The portion of SDK 4.7's EventingFunctionManager used by CouchSet. */
79
+ export interface EventingFunctionManagerLike {
80
+ upsertFunction(functionDefinition: EventingFunction): Promise<void>;
81
+ dropFunction(name: string): Promise<void>;
82
+ getAllFunctions(): Promise<EventingFunction[]>;
83
+ deployFunction(name: string): Promise<void>;
84
+ undeployFunction(name: string): Promise<void>;
85
+ pauseFunction(name: string): Promise<void>;
86
+ resumeFunction(name: string): Promise<void>;
87
+ functionsStatus(): Promise<{
88
+ functions: EventingFunctionState[];
89
+ }>;
90
+ }
91
+ /** A minimal client shape that lets Eventing acquire the connected SDK cluster. */
92
+ export interface EventingClient {
93
+ ready(): Promise<any>;
94
+ getConnection(): {
95
+ cluster: {
96
+ eventingFunctions?: () => EventingFunctionManager;
97
+ };
98
+ };
99
+ }
100
+ /**
101
+ * Declarative Eventing reconciler backed by the SDK 4.7 EventingFunctionManager.
102
+ * It only manages names starting with its namespace prefix.
103
+ */
104
+ export declare class Eventing {
105
+ private readonly definitionsByName;
106
+ private readonly eventingMetadataKeyspace;
107
+ private readonly lifecyclePollIntervalMs;
108
+ private readonly lifecycleTimeoutMs;
109
+ private readonly prefix;
110
+ private readonly client?;
111
+ private readonly explicitManager?;
112
+ constructor(client: EventingClient | undefined, options: EventingOptions);
113
+ /** Logical namespace that owns this controller's physical functions. */
114
+ get namespace(): string;
115
+ /** A copy of registered, code-only declarations. This performs no I/O. */
116
+ definitions(): EventingDefinition[];
117
+ /** Converts a logical declaration name into its Couchbase function name. */
118
+ physicalName(name: string): string;
119
+ /** Registers or replaces an in-memory manifest declaration without I/O. */
120
+ register(definition: EventingDefinition): EventingDefinition;
121
+ /** Alias for register(), matching the declaration-oriented API vocabulary. */
122
+ define(definition: EventingDefinition): EventingDefinition;
123
+ apply(options?: EventingApplyOptions): Promise<EventingReport>;
124
+ apply(definition: EventingDefinition, options?: EventingApplyOptions): Promise<EventingReport>;
125
+ /** Temporarily disables one namespace-owned Eventing function. */
126
+ pause(name: string): Promise<EventingReport>;
127
+ /**
128
+ * Intentionally undeploys then deletes one namespace-owned function.
129
+ * Undeployment erases Couchbase Eventing timers and checkpoints.
130
+ */
131
+ remove(name: string): Promise<EventingReport>;
132
+ private reconcile;
133
+ private prune;
134
+ private matches;
135
+ private sdkDefinition;
136
+ private metadataKeyspace;
137
+ private manager;
138
+ private states;
139
+ /**
140
+ * Management requests acknowledge receipt, not necessarily completion. Do
141
+ * not issue the next incompatible Eventing operation until status confirms
142
+ * that Couchbase has converged.
143
+ */
144
+ private waitForLifecycle;
145
+ /**
146
+ * Couchbase Server may turn a paused function into an undeployed function
147
+ * when upsert persists new code/settings/bindings. Inspect that post-upsert
148
+ * state rather than assuming resume is legal; deploy is the compatible
149
+ * activation operation in that case.
150
+ */
151
+ private activateAfterUpsert;
152
+ /**
153
+ * A live function with no status row is unknown, not safely undeployed.
154
+ * Poll for a positive row; a known transitional row remains an immediate
155
+ * blocker so callers do not race an operator's in-progress lifecycle call.
156
+ */
157
+ private stableLifecycle;
158
+ /** Waits for a stable state caused by this controller's own upsert call. */
159
+ private waitForStableLifecycle;
160
+ private record;
161
+ private outcome;
162
+ private owns;
163
+ private logicalName;
164
+ private assertDefinition;
165
+ private assertLogicalName;
166
+ private assertStable;
167
+ private isDefinition;
168
+ private positiveNumber;
169
+ private nonNegativeNumber;
170
+ }
171
+ /**
172
+ * Construct an Eventing control plane from a CouchSet client. The client is
173
+ * used only to obtain the SDK EventingFunctionManager after `ready()`.
174
+ */
175
+ export declare const createEventing: (client: EventingClient, options: EventingOptions) => Eventing;
176
+ /** Construct an Eventing control plane around an application-owned SDK manager. */
177
+ export declare const createEventingWithManager: (options: EventingOptions) => Eventing;
178
+ /** A small helper that makes Eventing definitions read as manifest declarations. */
179
+ export declare const defineEventingFunction: (definition: EventingDefinition) => EventingDefinition;