quidproquo-core 0.1.25 → 0.1.27
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/lib/commonjs/actions/keyValueStore/askKeyValueStoreQuery.d.ts +2 -1
- package/lib/commonjs/actions/keyValueStore/askKeyValueStoreQuery.js +1 -0
- package/lib/commonjs/actions/keyValueStore/askKeyValueStoreQuery.js.map +1 -1
- package/lib/commonjs/actions/platform/PlatformActionType.d.ts +2 -1
- package/lib/commonjs/actions/platform/PlatformActionType.js +1 -0
- package/lib/commonjs/actions/platform/PlatformActionType.js.map +1 -1
- package/lib/commonjs/actions/platform/askDelay.d.ts +1 -1
- package/lib/commonjs/actions/platform/askPlatformGetName.d.ts +8 -0
- package/lib/commonjs/actions/platform/askPlatformGetName.js +16 -0
- package/lib/commonjs/actions/platform/askPlatformGetName.js.map +1 -0
- package/lib/commonjs/actions/platform/index.d.ts +1 -0
- package/lib/commonjs/actions/platform/index.js +1 -0
- package/lib/commonjs/actions/platform/index.js.map +1 -1
- package/lib/commonjs/config/settings/keyValueStore.d.ts +6 -2
- package/lib/commonjs/config/settings/keyValueStore.js +22 -6
- package/lib/commonjs/config/settings/keyValueStore.js.map +1 -1
- package/lib/commonjs/config/settings/storageDrive.d.ts +4 -2
- package/lib/commonjs/config/settings/storageDrive.js +9 -3
- package/lib/commonjs/config/settings/storageDrive.js.map +1 -1
- package/lib/commonjs/logic/index.d.ts +1 -0
- package/lib/commonjs/logic/index.js +1 -0
- package/lib/commonjs/logic/index.js.map +1 -1
- package/lib/commonjs/logic/keyValueStore/KvsIndexNotFoundError.d.ts +5 -0
- package/lib/commonjs/logic/keyValueStore/KvsIndexNotFoundError.js +13 -0
- package/lib/commonjs/logic/keyValueStore/KvsIndexNotFoundError.js.map +1 -0
- package/lib/commonjs/logic/keyValueStore/flattenKvsQueryConditions.d.ts +3 -0
- package/lib/commonjs/logic/keyValueStore/flattenKvsQueryConditions.js +15 -0
- package/lib/commonjs/logic/keyValueStore/flattenKvsQueryConditions.js.map +1 -0
- package/lib/commonjs/logic/keyValueStore/index.d.ts +3 -0
- package/lib/commonjs/logic/keyValueStore/index.js +20 -0
- package/lib/commonjs/logic/keyValueStore/index.js.map +1 -0
- package/lib/commonjs/logic/keyValueStore/resolveKvsQueryIndex.d.ts +10 -0
- package/lib/commonjs/logic/keyValueStore/resolveKvsQueryIndex.js +31 -0
- package/lib/commonjs/logic/keyValueStore/resolveKvsQueryIndex.js.map +1 -0
- package/lib/commonjs/logic/scope/InvalidScopeError.d.ts +7 -1
- package/lib/commonjs/logic/scope/InvalidScopeError.js +22 -0
- package/lib/commonjs/logic/scope/InvalidScopeError.js.map +1 -1
- package/lib/commonjs/logic/scope/fileScopeGate.d.ts +8 -0
- package/lib/commonjs/logic/scope/fileScopeGate.js +35 -0
- package/lib/commonjs/logic/scope/fileScopeGate.js.map +1 -0
- package/lib/commonjs/logic/scope/index.d.ts +3 -3
- package/lib/commonjs/logic/scope/index.js +3 -3
- package/lib/commonjs/logic/scope/index.js.map +1 -1
- package/lib/commonjs/logic/scope/kvsScopeGate.d.ts +9 -3
- package/lib/commonjs/logic/scope/kvsScopeGate.js +48 -35
- package/lib/commonjs/logic/scope/kvsScopeGate.js.map +1 -1
- package/lib/commonjs/logic/scope/kvsScopeRules.d.ts +61 -0
- package/lib/commonjs/logic/scope/kvsScopeRules.js +232 -0
- package/lib/commonjs/logic/scope/kvsScopeRules.js.map +1 -0
- package/lib/commonjs/logic/scope/splitScopedFilePath.d.ts +11 -0
- package/lib/commonjs/logic/scope/splitScopedFilePath.js +21 -0
- package/lib/commonjs/logic/scope/splitScopedFilePath.js.map +1 -0
- package/lib/commonjs/logic/scope/validateScopeSegment.js +4 -4
- package/lib/commonjs/logic/scope/validateScopeSegment.js.map +1 -1
- package/lib/commonjs/types/Brand.d.ts +40 -0
- package/lib/commonjs/types/Brand.js +3 -0
- package/lib/commonjs/types/Brand.js.map +1 -0
- package/lib/commonjs/types/index.d.ts +1 -0
- package/lib/commonjs/types/index.js +1 -0
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/commonjs/validators/createBrandGuard.d.ts +6 -0
- package/lib/commonjs/validators/createBrandGuard.js +11 -0
- package/lib/commonjs/validators/createBrandGuard.js.map +1 -0
- package/lib/commonjs/validators/index.d.ts +1 -0
- package/lib/commonjs/validators/index.js +1 -0
- package/lib/commonjs/validators/index.js.map +1 -1
- package/lib/esm/actions/keyValueStore/askKeyValueStoreQuery.d.ts +2 -1
- package/lib/esm/actions/keyValueStore/askKeyValueStoreQuery.js +1 -0
- package/lib/esm/actions/keyValueStore/askKeyValueStoreQuery.js.map +1 -1
- package/lib/esm/actions/platform/PlatformActionType.d.ts +2 -1
- package/lib/esm/actions/platform/PlatformActionType.js +1 -0
- package/lib/esm/actions/platform/PlatformActionType.js.map +1 -1
- package/lib/esm/actions/platform/askDelay.d.ts +1 -1
- package/lib/esm/actions/platform/askPlatformGetName.d.ts +8 -0
- package/lib/esm/actions/platform/askPlatformGetName.js +13 -0
- package/lib/esm/actions/platform/askPlatformGetName.js.map +1 -0
- package/lib/esm/actions/platform/index.d.ts +1 -0
- package/lib/esm/actions/platform/index.js +1 -0
- package/lib/esm/actions/platform/index.js.map +1 -1
- package/lib/esm/config/settings/keyValueStore.d.ts +6 -2
- package/lib/esm/config/settings/keyValueStore.js +32 -15
- package/lib/esm/config/settings/keyValueStore.js.map +1 -1
- package/lib/esm/config/settings/storageDrive.d.ts +4 -2
- package/lib/esm/config/settings/storageDrive.js +20 -12
- package/lib/esm/config/settings/storageDrive.js.map +1 -1
- package/lib/esm/logic/index.d.ts +1 -0
- package/lib/esm/logic/index.js +1 -0
- package/lib/esm/logic/index.js.map +1 -1
- package/lib/esm/logic/keyValueStore/KvsIndexNotFoundError.d.ts +5 -0
- package/lib/esm/logic/keyValueStore/KvsIndexNotFoundError.js +9 -0
- package/lib/esm/logic/keyValueStore/KvsIndexNotFoundError.js.map +1 -0
- package/lib/esm/logic/keyValueStore/flattenKvsQueryConditions.d.ts +3 -0
- package/lib/esm/logic/keyValueStore/flattenKvsQueryConditions.js +11 -0
- package/lib/esm/logic/keyValueStore/flattenKvsQueryConditions.js.map +1 -0
- package/lib/esm/logic/keyValueStore/index.d.ts +3 -0
- package/lib/esm/logic/keyValueStore/index.js +4 -0
- package/lib/esm/logic/keyValueStore/index.js.map +1 -0
- package/lib/esm/logic/keyValueStore/resolveKvsQueryIndex.d.ts +10 -0
- package/lib/esm/logic/keyValueStore/resolveKvsQueryIndex.js +26 -0
- package/lib/esm/logic/keyValueStore/resolveKvsQueryIndex.js.map +1 -0
- package/lib/esm/logic/scope/InvalidScopeError.d.ts +7 -1
- package/lib/esm/logic/scope/InvalidScopeError.js +22 -0
- package/lib/esm/logic/scope/InvalidScopeError.js.map +1 -1
- package/lib/esm/logic/scope/fileScopeGate.d.ts +8 -0
- package/lib/esm/logic/scope/fileScopeGate.js +30 -0
- package/lib/esm/logic/scope/fileScopeGate.js.map +1 -0
- package/lib/esm/logic/scope/index.d.ts +3 -3
- package/lib/esm/logic/scope/index.js +3 -3
- package/lib/esm/logic/scope/index.js.map +1 -1
- package/lib/esm/logic/scope/kvsScopeGate.d.ts +9 -3
- package/lib/esm/logic/scope/kvsScopeGate.js +43 -32
- package/lib/esm/logic/scope/kvsScopeGate.js.map +1 -1
- package/lib/esm/logic/scope/kvsScopeRules.d.ts +61 -0
- package/lib/esm/logic/scope/kvsScopeRules.js +220 -0
- package/lib/esm/logic/scope/kvsScopeRules.js.map +1 -0
- package/lib/esm/logic/scope/splitScopedFilePath.d.ts +11 -0
- package/lib/esm/logic/scope/splitScopedFilePath.js +18 -0
- package/lib/esm/logic/scope/splitScopedFilePath.js.map +1 -0
- package/lib/esm/logic/scope/validateScopeSegment.js +4 -4
- package/lib/esm/logic/scope/validateScopeSegment.js.map +1 -1
- package/lib/esm/types/Brand.d.ts +40 -0
- package/lib/esm/types/Brand.js +2 -0
- package/lib/esm/types/Brand.js.map +1 -0
- package/lib/esm/types/index.d.ts +1 -0
- package/lib/esm/types/index.js +1 -0
- package/lib/esm/types/index.js.map +1 -1
- package/lib/esm/validators/createBrandGuard.d.ts +6 -0
- package/lib/esm/validators/createBrandGuard.js +8 -0
- package/lib/esm/validators/createBrandGuard.js.map +1 -0
- package/lib/esm/validators/index.d.ts +1 -0
- package/lib/esm/validators/index.js +1 -0
- package/lib/esm/validators/index.js.map +1 -1
- package/package.json +2 -2
- package/lib/commonjs/logic/scope/scopedKvsQueryOperation.d.ts +0 -42
- package/lib/commonjs/logic/scope/scopedKvsQueryOperation.js +0 -128
- package/lib/commonjs/logic/scope/scopedKvsQueryOperation.js.map +0 -1
- package/lib/commonjs/logic/scope/scopedKvsTranslator.d.ts +0 -32
- package/lib/commonjs/logic/scope/scopedKvsTranslator.js +0 -60
- package/lib/commonjs/logic/scope/scopedKvsTranslator.js.map +0 -1
- package/lib/commonjs/logic/scope/scopedKvsValue.d.ts +0 -12
- package/lib/commonjs/logic/scope/scopedKvsValue.js +0 -101
- package/lib/commonjs/logic/scope/scopedKvsValue.js.map +0 -1
- package/lib/esm/logic/scope/scopedKvsQueryOperation.d.ts +0 -42
- package/lib/esm/logic/scope/scopedKvsQueryOperation.js +0 -125
- package/lib/esm/logic/scope/scopedKvsQueryOperation.js.map +0 -1
- package/lib/esm/logic/scope/scopedKvsTranslator.d.ts +0 -32
- package/lib/esm/logic/scope/scopedKvsTranslator.js +0 -62
- package/lib/esm/logic/scope/scopedKvsTranslator.js.map +0 -1
- package/lib/esm/logic/scope/scopedKvsValue.d.ts +0 -12
- package/lib/esm/logic/scope/scopedKvsValue.js +0 -91
- package/lib/esm/logic/scope/scopedKvsValue.js.map +0 -1
|
@@ -9,11 +9,12 @@ export type KeyValueStoreQueryOptions = {
|
|
|
9
9
|
nextPageKey?: string;
|
|
10
10
|
filter?: KvsQueryOperation;
|
|
11
11
|
scope?: string;
|
|
12
|
+
indexName?: string;
|
|
12
13
|
consistentRead?: boolean;
|
|
13
14
|
};
|
|
14
15
|
export declare const askKeyValueStoreQueryBase: import("../..").ActionRequesterFunction<KeyValueStoreActionType.Query, [keyValueStoreName: string, keyCondition: KvsQueryOperation, options?: KeyValueStoreQueryOptions | undefined], {
|
|
15
16
|
keyValueStoreName: string;
|
|
16
17
|
keyCondition: KvsQueryOperation;
|
|
17
18
|
options: KeyValueStoreQueryOptions | undefined;
|
|
18
|
-
}, QpqPagedData<unknown>, "ResourceNotFound" | "ServiceUnavailable" | "InvalidScope" | "StoreNotFound">;
|
|
19
|
+
}, QpqPagedData<unknown>, "ResourceNotFound" | "ServiceUnavailable" | "InvalidScope" | "StoreNotFound" | "IndexNotFound">;
|
|
19
20
|
export declare function askKeyValueStoreQuery<KvsItem>(keyValueStoreName: string, keyCondition: KvsQueryOperation, options?: KeyValueStoreQueryOptions): AskResponse<QpqPagedData<KvsItem>>;
|
|
@@ -11,6 +11,7 @@ exports.askKeyValueStoreQueryBase = (0, createActionRequester_1.createActionRequ
|
|
|
11
11
|
'ResourceNotFound', // the underlying table does not exist
|
|
12
12
|
'InvalidScope', // scope is malformed or the store's partition key is not string-typed
|
|
13
13
|
'StoreNotFound', // the store is not declared in the qpq config (misconfiguration)
|
|
14
|
+
'IndexNotFound', // `indexName` names an index the store doesn't declare (misconfiguration)
|
|
14
15
|
],
|
|
15
16
|
getPayload: (keyValueStoreName, keyCondition, options) => ({
|
|
16
17
|
keyValueStoreName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"askKeyValueStoreQuery.js","sourceRoot":"","sources":["../../../../src/actions/keyValueStore/askKeyValueStoreQuery.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"askKeyValueStoreQuery.js","sourceRoot":"","sources":["../../../../src/actions/keyValueStore/askKeyValueStoreQuery.ts"],"names":[],"mappings":";;;AAmDA,sDAOC;AAxDD,mFAAgF;AAChF,uEAAoE;AA8BvD,QAAA,yBAAyB,GAAG,IAAA,6CAAqB,GAAyB,CAAC;IACtF,UAAU,EAAE,iDAAuB,CAAC,KAAK;IACzC,UAAU,EAAE;QACV,oBAAoB,EAAE,uCAAuC;QAC7D,kBAAkB,EAAE,sCAAsC;QAC1D,cAAc,EAAE,sEAAsE;QACtF,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,0EAA0E;KAC5F;IACD,UAAU,EAAE,CAAC,iBAAyB,EAAE,YAA+B,EAAE,OAAmC,EAAE,EAAE,CAAC,CAAC;QAChH,iBAAiB;QACjB,YAAY;QACZ,OAAO;KACR,CAAC;CACH,CAAC,CAAC;AAEH,uFAAuF;AACvF,6DAA6D;AAC7D,QAAe,CAAC,CAAC,qBAAqB,CACpC,iBAAyB,EAEzB,YAA+B,EAC/B,OAAmC;IAEnC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAA,iCAAyB,EAAC,iBAAiB,EAAE,YAAY,EAAE,OAAO,CAAC,CAA0B,CAAC;AAC/G,CAAC","sourcesContent":["import { QpqPagedData } from '../../types/QpqPagedData';\nimport { AskResponse } from '../../types/StorySession';\nimport { createActionRequester } from '../../types/utils/createActionRequester';\nimport { KeyValueStoreActionType } from './KeyValueStoreActionType';\nimport { KvsQueryOperation } from './types';\n\nexport type KeyValueStoreQueryOptions = {\n // Accepted but not implemented: no processor applies a TTL to query results.\n ttlInSeconds?: number;\n sortAscending?: boolean;\n limit?: number;\n nextPageKey?: string;\n filter?: KvsQueryOperation;\n // Composed into partition-key conditions by the processor; requires a string-typed partition key.\n scope?: string;\n // Query the declared index with this name (which defaults to its partition key attribute) and read in\n // its sort order. Without it the table, or else the first index, whose keys cover the key condition\n // serves it, so an index sharing the table's keys is only used when named here.\n indexName?: string;\n // Read the writer's own most recent writes, at the cost of a slower and (on DynamoDB) doubly-charged\n // read.\n //\n // Default reads are EVENTUALLY consistent, which is right for a viewer and wrong for a caller that just\n // wrote and is now reading back to decide something. That case is not hypothetical: a flow run appends\n // its terminal event and immediately re-lists the log to fold the outcome, and under load the terminal\n // event is intermittently not yet visible — so a run that succeeded reads back as having no outcome at\n // all, with nothing recorded to explain it.\n //\n // Use it for read-your-own-writes and for any fold used as a COORDINATION primitive (deciding \"am I\n // last\", \"did this finish\"). Do not use it for ordinary reads.\n consistentRead?: boolean;\n};\n\nexport const askKeyValueStoreQueryBase = createActionRequester<QpqPagedData<unknown>>()({\n actionType: KeyValueStoreActionType.Query,\n errorTypes: [\n 'ServiceUnavailable', // DynamoDB internal error / throttling\n 'ResourceNotFound', // the underlying table does not exist\n 'InvalidScope', // scope is malformed or the store's partition key is not string-typed\n 'StoreNotFound', // the store is not declared in the qpq config (misconfiguration)\n 'IndexNotFound', // `indexName` names an index the store doesn't declare (misconfiguration)\n ],\n getPayload: (keyValueStoreName: string, keyCondition: KvsQueryOperation, options?: KeyValueStoreQueryOptions) => ({\n keyValueStoreName,\n keyCondition,\n options,\n }),\n});\n\n// The stored item shape is only known to the caller, so the base returns unknown items\n// and this story casts the page to what the caller declared.\nexport function* askKeyValueStoreQuery<KvsItem>(\n keyValueStoreName: string,\n\n keyCondition: KvsQueryOperation,\n options?: KeyValueStoreQueryOptions,\n): AskResponse<QpqPagedData<KvsItem>> {\n return (yield* askKeyValueStoreQueryBase(keyValueStoreName, keyCondition, options)) as QpqPagedData<KvsItem>;\n}\n"]}
|
|
@@ -4,5 +4,6 @@ exports.PlatformActionType = void 0;
|
|
|
4
4
|
var PlatformActionType;
|
|
5
5
|
(function (PlatformActionType) {
|
|
6
6
|
PlatformActionType["Delay"] = "@quidproquo-core/Platform/Delay";
|
|
7
|
+
PlatformActionType["GetName"] = "@quidproquo-core/Platform/GetName";
|
|
7
8
|
})(PlatformActionType || (exports.PlatformActionType = PlatformActionType = {}));
|
|
8
9
|
//# sourceMappingURL=PlatformActionType.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformActionType.js","sourceRoot":"","sources":["../../../../src/actions/platform/PlatformActionType.ts"],"names":[],"mappings":";;;AAAA,IAAY,
|
|
1
|
+
{"version":3,"file":"PlatformActionType.js","sourceRoot":"","sources":["../../../../src/actions/platform/PlatformActionType.ts"],"names":[],"mappings":";;;AAAA,IAAY,kBAGX;AAHD,WAAY,kBAAkB;IAC5B,+DAAyC,CAAA;IACzC,mEAA6C,CAAA;AAC/C,CAAC,EAHW,kBAAkB,kCAAlB,kBAAkB,QAG7B","sourcesContent":["export enum PlatformActionType {\n Delay = '@quidproquo-core/Platform/Delay',\n GetName = '@quidproquo-core/Platform/GetName',\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { PlatformActionType } from './PlatformActionType';
|
|
2
|
-
export declare const askDelay: import("../../types").ActionRequesterFunction<PlatformActionType, [timeMs: number], {
|
|
2
|
+
export declare const askDelay: import("../../types").ActionRequesterFunction<PlatformActionType.Delay, [timeMs: number], {
|
|
3
3
|
timeMs: number;
|
|
4
4
|
}, void, never>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PlatformActionType } from './PlatformActionType';
|
|
2
|
+
/**
|
|
3
|
+
* The name of the runtime executing the story, as its action processor set declares it.
|
|
4
|
+
* An opaque string a story compares against a known constant to skip or degrade work a
|
|
5
|
+
* platform cannot do (a smoke test with no local equivalent, say). Never branch on it
|
|
6
|
+
* for ordinary logic; that is what action processors are for.
|
|
7
|
+
*/
|
|
8
|
+
export declare const askPlatformGetName: import("../../types").ActionRequesterFunction<PlatformActionType.GetName, [], {}, string, never>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.askPlatformGetName = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const PlatformActionType_1 = require("./PlatformActionType");
|
|
6
|
+
/**
|
|
7
|
+
* The name of the runtime executing the story, as its action processor set declares it.
|
|
8
|
+
* An opaque string a story compares against a known constant to skip or degrade work a
|
|
9
|
+
* platform cannot do (a smoke test with no local equivalent, say). Never branch on it
|
|
10
|
+
* for ordinary logic; that is what action processors are for.
|
|
11
|
+
*/
|
|
12
|
+
exports.askPlatformGetName = (0, types_1.createActionRequester)()({
|
|
13
|
+
actionType: PlatformActionType_1.PlatformActionType.GetName,
|
|
14
|
+
getPayload: () => ({}),
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=askPlatformGetName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"askPlatformGetName.js","sourceRoot":"","sources":["../../../../src/actions/platform/askPlatformGetName.ts"],"names":[],"mappings":";;;AAAA,uCAAoD;AACpD,6DAA0D;AAE1D;;;;;GAKG;AACU,QAAA,kBAAkB,GAAG,IAAA,6BAAqB,GAAU,CAAC;IAChE,UAAU,EAAE,uCAAkB,CAAC,OAAO;IACtC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;CACvB,CAAC,CAAC","sourcesContent":["import { createActionRequester } from '../../types';\nimport { PlatformActionType } from './PlatformActionType';\n\n/**\n * The name of the runtime executing the story, as its action processor set declares it.\n * An opaque string a story compares against a known constant to skip or degrade work a\n * platform cannot do (a smoke test with no local equivalent, say). Never branch on it\n * for ordinary logic; that is what action processors are for.\n */\nexport const askPlatformGetName = createActionRequester<string>()({\n actionType: PlatformActionType.GetName,\n getPayload: () => ({}),\n});\n"]}
|
|
@@ -15,5 +15,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./askDelay"), exports);
|
|
18
|
+
__exportStar(require("./askPlatformGetName"), exports);
|
|
18
19
|
__exportStar(require("./PlatformActionType"), exports);
|
|
19
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/actions/platform/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,uDAAqC","sourcesContent":["export * from './askDelay';\nexport * from './PlatformActionType';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/actions/platform/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,uDAAqC;AACrC,uDAAqC","sourcesContent":["export * from './askDelay';\nexport * from './askPlatformGetName';\nexport * from './PlatformActionType';\n"]}
|
|
@@ -6,12 +6,14 @@ export type KvsKey<T extends object = any> = {
|
|
|
6
6
|
type: KvsKeyType;
|
|
7
7
|
};
|
|
8
8
|
export type KvsIndex<T extends object = any> = {
|
|
9
|
+
name: string;
|
|
9
10
|
partitionKey: KvsKey<T>;
|
|
10
11
|
sortKey?: KvsKey<T>;
|
|
11
12
|
};
|
|
12
13
|
export declare const kvsKey: <T extends object = any>(key: KeyOf<T>, type?: KvsKeyType) => KvsKey<T>;
|
|
13
14
|
type CompositeKvsKey<T extends object = any> = KvsKey<T> | KeyOf<T>;
|
|
14
15
|
type CompositeCompositeKvsIndex<T extends object = any> = {
|
|
16
|
+
name?: string;
|
|
15
17
|
partitionKey: CompositeKvsKey<T>;
|
|
16
18
|
sortKey?: CompositeKvsKey<T>;
|
|
17
19
|
};
|
|
@@ -57,7 +59,8 @@ export interface QPQConfigAdvancedKeyValueStoreSettings<T extends object = any>
|
|
|
57
59
|
owner?: CrossModuleOwner;
|
|
58
60
|
ttlAttribute?: string;
|
|
59
61
|
disablePointInTimeRecovery?: boolean;
|
|
60
|
-
|
|
62
|
+
cryptoKeyName?: string;
|
|
63
|
+
scoped?: boolean;
|
|
61
64
|
onStream?: KvsStreamSettings;
|
|
62
65
|
}
|
|
63
66
|
export interface KeyValueStoreQPQConfigSetting<T extends object = any> extends QPQConfigSetting {
|
|
@@ -68,7 +71,8 @@ export interface KeyValueStoreQPQConfigSetting<T extends object = any> extends Q
|
|
|
68
71
|
global: boolean;
|
|
69
72
|
ttlAttribute?: string;
|
|
70
73
|
disablePointInTimeRecovery: boolean;
|
|
71
|
-
|
|
74
|
+
cryptoKeyName?: string;
|
|
75
|
+
scoped: boolean;
|
|
72
76
|
onStream?: KvsStreamSettings;
|
|
73
77
|
}
|
|
74
78
|
export declare const defineKeyValueStore: <T extends object = any>(keyValueStoreName: string, partitionKey: CompositeKvsKey<T>, sortKeys?: CompositeKvsKey<T>[], options?: QPQConfigAdvancedKeyValueStoreSettings<T>) => KeyValueStoreQPQConfigSetting<T>;
|
|
@@ -19,32 +19,48 @@ const isCompositeKvsIndexACompositeCompositeKvsIndex = (compositeKvsIndex) => {
|
|
|
19
19
|
return typeof compositeKvsIndex !== 'string';
|
|
20
20
|
};
|
|
21
21
|
const convertCompositeKvsIndexToKvsIndex = (compositeKvsIndex) => {
|
|
22
|
+
var _a;
|
|
22
23
|
if (!isCompositeKvsIndexACompositeCompositeKvsIndex(compositeKvsIndex)) {
|
|
23
24
|
return {
|
|
25
|
+
name: compositeKvsIndex,
|
|
24
26
|
partitionKey: (0, exports.kvsKey)(compositeKvsIndex, 'string'),
|
|
25
27
|
};
|
|
26
28
|
}
|
|
29
|
+
const partitionKey = convertCompositeKvsKeyToKvsKey(compositeKvsIndex.partitionKey);
|
|
27
30
|
return {
|
|
28
|
-
|
|
31
|
+
name: (_a = compositeKvsIndex.name) !== null && _a !== void 0 ? _a : partitionKey.key,
|
|
32
|
+
partitionKey,
|
|
29
33
|
sortKey: compositeKvsIndex.sortKey ? convertCompositeKvsKeyToKvsKey(compositeKvsIndex.sortKey) : undefined,
|
|
30
34
|
};
|
|
31
35
|
};
|
|
32
36
|
const defineKeyValueStore = (keyValueStoreName, partitionKey, sortKeys = [], options) => {
|
|
33
37
|
var _a, _b, _c, _d;
|
|
34
|
-
|
|
38
|
+
const tablePartitionKey = convertCompositeKvsKeyToKvsKey(partitionKey);
|
|
39
|
+
const indexes = ((_a = options === null || options === void 0 ? void 0 : options.indexes) !== null && _a !== void 0 ? _a : []).map((convertCompositeKvsIndexToKvsIndex));
|
|
40
|
+
const duplicateIndexName = indexes.find((index, position) => indexes.findIndex((other) => other.name === index.name) !== position);
|
|
41
|
+
if (duplicateIndexName) {
|
|
42
|
+
throw new Error(`Key value store '${keyValueStoreName}' declares two indexes named '${duplicateIndexName.name}'; give one an explicit name`);
|
|
43
|
+
}
|
|
44
|
+
// A scoped store's indexes are partitioned per scope, which every backend can do
|
|
45
|
+
// for a string or number key but not a binary one.
|
|
46
|
+
if ((options === null || options === void 0 ? void 0 : options.scoped) && indexes.some((index) => index.partitionKey.type === 'binary' && index.partitionKey.key !== tablePartitionKey.key)) {
|
|
47
|
+
throw new Error(`Key value store '${keyValueStoreName}' is scoped, so its index partition keys must be strings or numbers`);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
35
50
|
configSettingType: QPQConfig_1.QPQCoreConfigSettingType.keyValueStore,
|
|
36
51
|
uniqueKey: keyValueStoreName,
|
|
37
52
|
keyValueStoreName,
|
|
38
|
-
partitionKey:
|
|
53
|
+
partitionKey: tablePartitionKey,
|
|
39
54
|
sortKeys: sortKeys.map((convertCompositeKvsKeyToKvsKey)),
|
|
40
|
-
indexes
|
|
55
|
+
indexes,
|
|
41
56
|
global: (_b = options === null || options === void 0 ? void 0 : options.global) !== null && _b !== void 0 ? _b : false,
|
|
42
57
|
owner: options === null || options === void 0 ? void 0 : options.owner,
|
|
43
58
|
ttlAttribute: options === null || options === void 0 ? void 0 : options.ttlAttribute,
|
|
44
59
|
disablePointInTimeRecovery: (_c = options === null || options === void 0 ? void 0 : options.disablePointInTimeRecovery) !== null && _c !== void 0 ? _c : false,
|
|
45
|
-
|
|
60
|
+
cryptoKeyName: options === null || options === void 0 ? void 0 : options.cryptoKeyName,
|
|
61
|
+
scoped: (_d = options === null || options === void 0 ? void 0 : options.scoped) !== null && _d !== void 0 ? _d : false,
|
|
46
62
|
onStream: options === null || options === void 0 ? void 0 : options.onStream,
|
|
47
|
-
}
|
|
63
|
+
};
|
|
48
64
|
};
|
|
49
65
|
exports.defineKeyValueStore = defineKeyValueStore;
|
|
50
66
|
//# sourceMappingURL=keyValueStore.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyValueStore.js","sourceRoot":"","sources":["../../../../src/config/settings/keyValueStore.ts"],"names":[],"mappings":";;;AACA,4CAAqG;AAmB9F,MAAM,MAAM,GAAG,CAAyB,GAAa,EAAE,OAAmB,QAAQ,EAAa,EAAE,CAAC,CAAC;IACxG,GAAG;IACH,IAAI;CACL,CAAC,CAAC;AAHU,QAAA,MAAM,UAGhB;AAWH,MAAM,8BAA8B,GAAG,CAAyB,eAAmC,EAAa,EAAE;IAChH,oBAAoB;IACpB,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,IAAA,cAAM,EAAI,eAA2B,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,sBAAsB;IACtB,OAAO,eAA4B,CAAC;AACtC,CAAC,CAAC;AAEF,MAAM,8CAA8C,GAAG,CACrD,iBAAuC,EACa,EAAE;IACtD,OAAO,OAAO,iBAAiB,KAAK,QAAQ,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,kCAAkC,GAAG,CAAyB,iBAAuC,EAAe,EAAE;IAC1H,IAAI,CAAC,8CAA8C,CAAI,iBAAiB,CAAC,EAAE,CAAC;QAC1E,OAAO;YACL,YAAY,EAAE,IAAA,cAAM,EAAI,iBAAiB,EAAE,QAAQ,CAAC;SACrD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY,EAAE,8BAA8B,CAAI,iBAAiB,CAAC,YAAY,CAAC;QAC/E,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9G,CAAC;AACJ,CAAC,CAAC;AA+EK,MAAM,mBAAmB,GAAG,CACjC,iBAAyB,EAEzB,YAAgC,EAChC,WAAiC,EAAE,EAEnC,OAAmD,EACjB,EAAE;;IAAC,OAAA,CAAC;QACtC,iBAAiB,EAAE,oCAAwB,CAAC,aAAa;QACzD,SAAS,EAAE,iBAAiB;QAE5B,iBAAiB;QAEjB,YAAY,EAAE,8BAA8B,CAAI,YAAY,CAAC;QAC7D,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAA,8BAAiC,CAAA,CAAC;QAEzD,OAAO,EAAE,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,mCAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA,kCAAqC,CAAA,CAAC;QAE5E,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,KAAK,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK;QAErB,YAAY,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAAY;QAEnC,0BAA0B,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,0BAA0B,mCAAI,KAAK;QAExE,UAAU,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,UAAU,mCAAI,KAAK;QAExC,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ;KAC5B,CAAC,CAAA;CAAA,CAAC;AA7BU,QAAA,mBAAmB,uBA6B7B","sourcesContent":["import { CrossModuleOwner, KeyOf, QpqFunctionRuntime } from '../../types';\nimport { QPQConfigAdvancedSettings, QPQConfigSetting, QPQCoreConfigSettingType } from '../QPQConfig';\n\n// TODO: When we put validation on the QPQConfig, we need to make sure\n// Key Length and Data Type: DynamoDB has limitations on key length and data type.\n// Your KvsKeyType only supports 'string', 'number', and 'binary' types. Make sure\n// that you're validating these in convertKvsKeyToDynamodbAttribute function and\n// also ensure that key length is within DynamoDB's specified limits.\n\nexport type KvsKeyType = 'string' | 'number' | 'binary';\nexport type KvsKey<T extends object = any> = {\n key: KeyOf<T>;\n type: KvsKeyType;\n};\n\nexport type KvsIndex<T extends object = any> = {\n partitionKey: KvsKey<T>;\n sortKey?: KvsKey<T>;\n};\n\nexport const kvsKey = <T extends object = any>(key: KeyOf<T>, type: KvsKeyType = 'string'): KvsKey<T> => ({\n key,\n type,\n});\n\ntype CompositeKvsKey<T extends object = any> = KvsKey<T> | KeyOf<T>;\n\ntype CompositeCompositeKvsIndex<T extends object = any> = {\n partitionKey: CompositeKvsKey<T>;\n sortKey?: CompositeKvsKey<T>;\n};\n\nexport type CompositeKvsIndex<T extends object = any> = KeyOf<T> | CompositeCompositeKvsIndex<T>;\n\nconst convertCompositeKvsKeyToKvsKey = <T extends object = any>(compositeKvsKey: CompositeKvsKey<T>): KvsKey<T> => {\n // Must be a keyof T\n if (typeof compositeKvsKey === 'string') {\n return kvsKey<T>(compositeKvsKey as KeyOf<T>, 'string');\n }\n\n // must be a KvsKey<T>\n return compositeKvsKey as KvsKey<T>;\n};\n\nconst isCompositeKvsIndexACompositeCompositeKvsIndex = <T extends object = any>(\n compositeKvsIndex: CompositeKvsIndex<T>,\n): compositeKvsIndex is CompositeCompositeKvsIndex<T> => {\n return typeof compositeKvsIndex !== 'string';\n};\n\nconst convertCompositeKvsIndexToKvsIndex = <T extends object = any>(compositeKvsIndex: CompositeKvsIndex<T>): KvsIndex<T> => {\n if (!isCompositeKvsIndexACompositeCompositeKvsIndex<T>(compositeKvsIndex)) {\n return {\n partitionKey: kvsKey<T>(compositeKvsIndex, 'string'),\n };\n }\n\n return {\n partitionKey: convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.partitionKey),\n sortKey: compositeKvsIndex.sortKey ? convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.sortKey) : undefined,\n };\n};\n\n/**\n * Change data capture on a store: the table gets a stream (NEW_AND_OLD_IMAGES) and\n * `runtime` is invoked with the changes.\n *\n * Records arrive in order PER PARTITION KEY, and different partition keys are processed\n * concurrently. A stream handler therefore gets one-writer-per-item serialisation for\n * free, which is what makes a stream the natural place to maintain a projection of a table\n * you only ever append to — no queue, no extra write on the append path, and no trigger to\n * lose, because the record exists precisely because the write happened.\n *\n * Mirrors defineStorageDrive's `onEvent`.\n */\nexport type KvsStreamSettings = {\n runtime: QpqFunctionRuntime;\n\n /**\n * Collapse each delivered batch down to ONE record per partition key, keeping the latest.\n *\n * Off by default: a generic consumer (audit trail, change notifications) needs to see\n * every change, and the framework should never silently drop records.\n *\n * On for a PROJECTION, where the payload that matters is \"this key changed\" and the\n * handler re-derives from source anyway. Without it, the batch is fanned back out into\n * one story run per record and the batching bought nothing: 500 appends to one document\n * would mean 500 re-derivations, each reading a log that grows as it goes. With it, that\n * batch is a single re-derivation.\n */\n coalesceByPartitionKey?: boolean;\n\n /** Records per invocation. DynamoDB streams allow up to 1000; the mapping default is 100. */\n batchSize?: number;\n\n /**\n * How long to wait accumulating records before invoking, 0 to 300 seconds. Trades\n * projection latency for far fewer invocations, and gives coalescing more to collapse.\n */\n maximumBatchingWindowInSeconds?: number;\n};\n\nexport interface QPQConfigAdvancedKeyValueStoreSettings<T extends object = any> extends QPQConfigAdvancedSettings {\n indexes?: CompositeKvsIndex<T>[];\n\n global?: boolean;\n\n owner?: CrossModuleOwner;\n\n ttlAttribute?: string;\n\n // Point-in-time recovery (35-day continuous backups) is on by default; set this to opt out.\n disablePointInTimeRecovery?: boolean;\n\n encryption?: boolean;\n\n // Turn on change data capture — see KvsStreamSettings. Absent means no stream is\n // created at all.\n onStream?: KvsStreamSettings;\n}\n\nexport interface KeyValueStoreQPQConfigSetting<T extends object = any> extends QPQConfigSetting {\n keyValueStoreName: string;\n\n partitionKey: KvsKey<T>;\n sortKeys: KvsKey<T>[];\n\n indexes: KvsIndex<T>[];\n\n global: boolean;\n\n ttlAttribute?: string;\n\n disablePointInTimeRecovery: boolean;\n\n encryption: boolean;\n\n onStream?: KvsStreamSettings;\n}\n\nexport const defineKeyValueStore = <T extends object = any>(\n keyValueStoreName: string,\n\n partitionKey: CompositeKvsKey<T>,\n sortKeys: CompositeKvsKey<T>[] = [],\n\n options?: QPQConfigAdvancedKeyValueStoreSettings<T>,\n): KeyValueStoreQPQConfigSetting<T> => ({\n configSettingType: QPQCoreConfigSettingType.keyValueStore,\n uniqueKey: keyValueStoreName,\n\n keyValueStoreName,\n\n partitionKey: convertCompositeKvsKeyToKvsKey<T>(partitionKey),\n sortKeys: sortKeys.map(convertCompositeKvsKeyToKvsKey<T>),\n\n indexes: (options?.indexes ?? []).map(convertCompositeKvsIndexToKvsIndex<T>),\n\n global: options?.global ?? false,\n\n owner: options?.owner,\n\n ttlAttribute: options?.ttlAttribute,\n\n disablePointInTimeRecovery: options?.disablePointInTimeRecovery ?? false,\n\n encryption: options?.encryption ?? false,\n\n onStream: options?.onStream,\n});\n"]}
|
|
1
|
+
{"version":3,"file":"keyValueStore.js","sourceRoot":"","sources":["../../../../src/config/settings/keyValueStore.ts"],"names":[],"mappings":";;;AACA,4CAAqG;AAqB9F,MAAM,MAAM,GAAG,CAAyB,GAAa,EAAE,OAAmB,QAAQ,EAAa,EAAE,CAAC,CAAC;IACxG,GAAG;IACH,IAAI;CACL,CAAC,CAAC;AAHU,QAAA,MAAM,UAGhB;AAaH,MAAM,8BAA8B,GAAG,CAAyB,eAAmC,EAAa,EAAE;IAChH,oBAAoB;IACpB,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,IAAA,cAAM,EAAI,eAA2B,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,sBAAsB;IACtB,OAAO,eAA4B,CAAC;AACtC,CAAC,CAAC;AAEF,MAAM,8CAA8C,GAAG,CACrD,iBAAuC,EACa,EAAE;IACtD,OAAO,OAAO,iBAAiB,KAAK,QAAQ,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,kCAAkC,GAAG,CAAyB,iBAAuC,EAAe,EAAE;;IAC1H,IAAI,CAAC,8CAA8C,CAAI,iBAAiB,CAAC,EAAE,CAAC;QAC1E,OAAO;YACL,IAAI,EAAE,iBAAiB;YACvB,YAAY,EAAE,IAAA,cAAM,EAAI,iBAAiB,EAAE,QAAQ,CAAC;SACrD,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,8BAA8B,CAAI,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAEvF,OAAO;QACL,IAAI,EAAE,MAAA,iBAAiB,CAAC,IAAI,mCAAI,YAAY,CAAC,GAAG;QAChD,YAAY;QACZ,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9G,CAAC;AACJ,CAAC,CAAC;AAuFK,MAAM,mBAAmB,GAAG,CACjC,iBAAyB,EAEzB,YAAgC,EAChC,WAAiC,EAAE,EAEnC,OAAmD,EACjB,EAAE;;IACpC,MAAM,iBAAiB,GAAG,8BAA8B,CAAI,YAAY,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,CAAC,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,mCAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA,kCAAqC,CAAA,CAAC,CAAC;IAEpF,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC;IACnI,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,oBAAoB,iBAAiB,iCAAiC,kBAAkB,CAAC,IAAI,8BAA8B,CAAC,CAAC;IAC/I,CAAC;IAED,iFAAiF;IACjF,mDAAmD;IACnD,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,KAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,YAAY,CAAC,GAAG,KAAK,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;QACzI,MAAM,IAAI,KAAK,CAAC,oBAAoB,iBAAiB,qEAAqE,CAAC,CAAC;IAC9H,CAAC;IAED,OAAO;QACL,iBAAiB,EAAE,oCAAwB,CAAC,aAAa;QACzD,SAAS,EAAE,iBAAiB;QAE5B,iBAAiB;QAEjB,YAAY,EAAE,iBAAiB;QAC/B,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAA,8BAAiC,CAAA,CAAC;QAEzD,OAAO;QAEP,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,KAAK,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK;QAErB,YAAY,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAAY;QAEnC,0BAA0B,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,0BAA0B,mCAAI,KAAK;QAExE,aAAa,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa;QACrC,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ;KAC5B,CAAC;AACJ,CAAC,CAAC;AA9CW,QAAA,mBAAmB,uBA8C9B","sourcesContent":["import { CrossModuleOwner, KeyOf, QpqFunctionRuntime } from '../../types';\nimport { QPQConfigAdvancedSettings, QPQConfigSetting, QPQCoreConfigSettingType } from '../QPQConfig';\n\n// TODO: When we put validation on the QPQConfig, we need to make sure\n// Key Length and Data Type: DynamoDB has limitations on key length and data type.\n// Your KvsKeyType only supports 'string', 'number', and 'binary' types. Make sure\n// that you're validating these in convertKvsKeyToDynamodbAttribute function and\n// also ensure that key length is within DynamoDB's specified limits.\n\nexport type KvsKeyType = 'string' | 'number' | 'binary';\nexport type KvsKey<T extends object = any> = {\n key: KeyOf<T>;\n type: KvsKeyType;\n};\n\nexport type KvsIndex<T extends object = any> = {\n // What the index is queried by (askKeyValueStoreQuery's `indexName` option) and deployed as.\n name: string;\n partitionKey: KvsKey<T>;\n sortKey?: KvsKey<T>;\n};\n\nexport const kvsKey = <T extends object = any>(key: KeyOf<T>, type: KvsKeyType = 'string'): KvsKey<T> => ({\n key,\n type,\n});\n\ntype CompositeKvsKey<T extends object = any> = KvsKey<T> | KeyOf<T>;\n\ntype CompositeCompositeKvsIndex<T extends object = any> = {\n // Defaults to the partition key attribute. Name an index when two share a partition key.\n name?: string;\n partitionKey: CompositeKvsKey<T>;\n sortKey?: CompositeKvsKey<T>;\n};\n\nexport type CompositeKvsIndex<T extends object = any> = KeyOf<T> | CompositeCompositeKvsIndex<T>;\n\nconst convertCompositeKvsKeyToKvsKey = <T extends object = any>(compositeKvsKey: CompositeKvsKey<T>): KvsKey<T> => {\n // Must be a keyof T\n if (typeof compositeKvsKey === 'string') {\n return kvsKey<T>(compositeKvsKey as KeyOf<T>, 'string');\n }\n\n // must be a KvsKey<T>\n return compositeKvsKey as KvsKey<T>;\n};\n\nconst isCompositeKvsIndexACompositeCompositeKvsIndex = <T extends object = any>(\n compositeKvsIndex: CompositeKvsIndex<T>,\n): compositeKvsIndex is CompositeCompositeKvsIndex<T> => {\n return typeof compositeKvsIndex !== 'string';\n};\n\nconst convertCompositeKvsIndexToKvsIndex = <T extends object = any>(compositeKvsIndex: CompositeKvsIndex<T>): KvsIndex<T> => {\n if (!isCompositeKvsIndexACompositeCompositeKvsIndex<T>(compositeKvsIndex)) {\n return {\n name: compositeKvsIndex,\n partitionKey: kvsKey<T>(compositeKvsIndex, 'string'),\n };\n }\n\n const partitionKey = convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.partitionKey);\n\n return {\n name: compositeKvsIndex.name ?? partitionKey.key,\n partitionKey,\n sortKey: compositeKvsIndex.sortKey ? convertCompositeKvsKeyToKvsKey<T>(compositeKvsIndex.sortKey) : undefined,\n };\n};\n\n/**\n * Change data capture on a store: the table gets a stream (NEW_AND_OLD_IMAGES) and\n * `runtime` is invoked with the changes.\n *\n * Records arrive in order PER PARTITION KEY, and different partition keys are processed\n * concurrently. A stream handler therefore gets one-writer-per-item serialisation for\n * free, which is what makes a stream the natural place to maintain a projection of a table\n * you only ever append to — no queue, no extra write on the append path, and no trigger to\n * lose, because the record exists precisely because the write happened.\n *\n * Mirrors defineStorageDrive's `onEvent`.\n */\nexport type KvsStreamSettings = {\n runtime: QpqFunctionRuntime;\n\n /**\n * Collapse each delivered batch down to ONE record per partition key, keeping the latest.\n *\n * Off by default: a generic consumer (audit trail, change notifications) needs to see\n * every change, and the framework should never silently drop records.\n *\n * On for a PROJECTION, where the payload that matters is \"this key changed\" and the\n * handler re-derives from source anyway. Without it, the batch is fanned back out into\n * one story run per record and the batching bought nothing: 500 appends to one document\n * would mean 500 re-derivations, each reading a log that grows as it goes. With it, that\n * batch is a single re-derivation.\n */\n coalesceByPartitionKey?: boolean;\n\n /** Records per invocation. DynamoDB streams allow up to 1000; the mapping default is 100. */\n batchSize?: number;\n\n /**\n * How long to wait accumulating records before invoking, 0 to 300 seconds. Trades\n * projection latency for far fewer invocations, and gives coalescing more to collapse.\n */\n maximumBatchingWindowInSeconds?: number;\n};\n\nexport interface QPQConfigAdvancedKeyValueStoreSettings<T extends object = any> extends QPQConfigAdvancedSettings {\n indexes?: CompositeKvsIndex<T>[];\n\n global?: boolean;\n\n owner?: CrossModuleOwner;\n\n ttlAttribute?: string;\n\n // Point-in-time recovery (35-day continuous backups) is on by default; set this to opt out.\n disablePointInTimeRecovery?: boolean;\n\n // Encrypt the table with the named defineCryptoKey instead of the provider's own managed\n // encryption, which always applies. The key must be declared in the same config, owned or\n // foreign; a foreign key's owning service must be deployed first.\n cryptoKeyName?: string;\n\n // Every action on this store must carry a scope; an unscoped call is refused rather\n // than hitting the unpartitioned rows. askKeyValueStoreScanAllScopes is exempt.\n scoped?: boolean;\n\n // Turn on change data capture — see KvsStreamSettings. Absent means no stream is\n // created at all.\n onStream?: KvsStreamSettings;\n}\n\nexport interface KeyValueStoreQPQConfigSetting<T extends object = any> extends QPQConfigSetting {\n keyValueStoreName: string;\n\n partitionKey: KvsKey<T>;\n sortKeys: KvsKey<T>[];\n\n indexes: KvsIndex<T>[];\n\n global: boolean;\n\n ttlAttribute?: string;\n\n disablePointInTimeRecovery: boolean;\n\n cryptoKeyName?: string;\n scoped: boolean;\n\n onStream?: KvsStreamSettings;\n}\n\nexport const defineKeyValueStore = <T extends object = any>(\n keyValueStoreName: string,\n\n partitionKey: CompositeKvsKey<T>,\n sortKeys: CompositeKvsKey<T>[] = [],\n\n options?: QPQConfigAdvancedKeyValueStoreSettings<T>,\n): KeyValueStoreQPQConfigSetting<T> => {\n const tablePartitionKey = convertCompositeKvsKeyToKvsKey<T>(partitionKey);\n const indexes = (options?.indexes ?? []).map(convertCompositeKvsIndexToKvsIndex<T>);\n\n const duplicateIndexName = indexes.find((index, position) => indexes.findIndex((other) => other.name === index.name) !== position);\n if (duplicateIndexName) {\n throw new Error(`Key value store '${keyValueStoreName}' declares two indexes named '${duplicateIndexName.name}'; give one an explicit name`);\n }\n\n // A scoped store's indexes are partitioned per scope, which every backend can do\n // for a string or number key but not a binary one.\n if (options?.scoped && indexes.some((index) => index.partitionKey.type === 'binary' && index.partitionKey.key !== tablePartitionKey.key)) {\n throw new Error(`Key value store '${keyValueStoreName}' is scoped, so its index partition keys must be strings or numbers`);\n }\n\n return {\n configSettingType: QPQCoreConfigSettingType.keyValueStore,\n uniqueKey: keyValueStoreName,\n\n keyValueStoreName,\n\n partitionKey: tablePartitionKey,\n sortKeys: sortKeys.map(convertCompositeKvsKeyToKvsKey<T>),\n\n indexes,\n\n global: options?.global ?? false,\n\n owner: options?.owner,\n\n ttlAttribute: options?.ttlAttribute,\n\n disablePointInTimeRecovery: options?.disablePointInTimeRecovery ?? false,\n\n cryptoKeyName: options?.cryptoKeyName,\n scoped: options?.scoped ?? false,\n\n onStream: options?.onStream,\n };\n};\n"]}
|
|
@@ -77,7 +77,8 @@ export interface QPQConfigAdvancedStorageDriveSettings extends QPQConfigAdvanced
|
|
|
77
77
|
global?: boolean;
|
|
78
78
|
onEvent?: StorageDriveEvents;
|
|
79
79
|
lifecycleRules?: StorageDriveLifecycleRule[];
|
|
80
|
-
|
|
80
|
+
cryptoKeyName?: string;
|
|
81
|
+
scoped?: boolean;
|
|
81
82
|
lockedDown?: boolean;
|
|
82
83
|
owner?: CrossModuleOwner<'storageDriveName'>;
|
|
83
84
|
}
|
|
@@ -87,7 +88,8 @@ export interface StorageDriveQPQConfigSetting extends QPQConfigSetting {
|
|
|
87
88
|
global: boolean;
|
|
88
89
|
onEvent?: StorageDriveEvents;
|
|
89
90
|
lifecycleRules?: StorageDriveLifecycleRule[];
|
|
90
|
-
|
|
91
|
+
cryptoKeyName?: string;
|
|
92
|
+
scoped: boolean;
|
|
91
93
|
lockedDown: boolean;
|
|
92
94
|
}
|
|
93
95
|
export declare const defineStorageDrive: (storageDrive: string, options?: QPQConfigAdvancedStorageDriveSettings) => StorageDriveQPQConfigSetting;
|
|
@@ -57,7 +57,12 @@ var StorageDriveTier;
|
|
|
57
57
|
})(StorageDriveTier || (exports.StorageDriveTier = StorageDriveTier = {}));
|
|
58
58
|
const defineStorageDrive = (storageDrive, options) => {
|
|
59
59
|
var _a, _b, _c;
|
|
60
|
-
|
|
60
|
+
// copyPath content is deployed straight to the bucket root, outside every
|
|
61
|
+
// scope, so it can never coexist with a scoped drive.
|
|
62
|
+
if ((options === null || options === void 0 ? void 0 : options.scoped) && options.copyPath) {
|
|
63
|
+
throw new Error(`Storage drive '${storageDrive}' cannot be both scoped and have a copyPath`);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
61
66
|
configSettingType: QPQConfig_1.QPQCoreConfigSettingType.storageDrive,
|
|
62
67
|
uniqueKey: storageDrive,
|
|
63
68
|
storageDrive,
|
|
@@ -65,10 +70,11 @@ const defineStorageDrive = (storageDrive, options) => {
|
|
|
65
70
|
global: (_a = options === null || options === void 0 ? void 0 : options.global) !== null && _a !== void 0 ? _a : false,
|
|
66
71
|
onEvent: options === null || options === void 0 ? void 0 : options.onEvent,
|
|
67
72
|
lifecycleRules: options === null || options === void 0 ? void 0 : options.lifecycleRules,
|
|
68
|
-
|
|
73
|
+
cryptoKeyName: options === null || options === void 0 ? void 0 : options.cryptoKeyName,
|
|
74
|
+
scoped: (_b = options === null || options === void 0 ? void 0 : options.scoped) !== null && _b !== void 0 ? _b : false,
|
|
69
75
|
lockedDown: (_c = options === null || options === void 0 ? void 0 : options.lockedDown) !== null && _c !== void 0 ? _c : false,
|
|
70
76
|
owner: (0, crossModuleUtils_1.convertCrossModuleOwnerToGenericResourceNameOverride)(options === null || options === void 0 ? void 0 : options.owner),
|
|
71
|
-
}
|
|
77
|
+
};
|
|
72
78
|
};
|
|
73
79
|
exports.defineStorageDrive = defineStorageDrive;
|
|
74
80
|
//# sourceMappingURL=storageDrive.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageDrive.js","sourceRoot":"","sources":["../../../../src/config/settings/storageDrive.ts"],"names":[],"mappings":";;;AACA,4CAAqG;AACrG,gEAAiG;AAEjG;;GAEG;AACH,IAAY,gBAqDX;AArDD,WAAY,gBAAgB;IAC1B;;;OAGG;IACH,uCAAmB,CAAA;IAEnB;;;;;OAKG;IACH,2DAAuC,CAAA;IAEvC;;;;OAIG;IACH,mFAA+D,CAAA;IAE/D;;;;;OAKG;IACH,iDAA6B,CAAA;IAE7B;;;;;OAKG;IACH,+EAA2D,CAAA;IAE3D;;;;;OAKG;IACH,2DAAuC,CAAA;IAEvC;;;;;OAKG;IACH,mDAA+B,CAAA;AACjC,CAAC,EArDW,gBAAgB,gCAAhB,gBAAgB,QAqD3B;
|
|
1
|
+
{"version":3,"file":"storageDrive.js","sourceRoot":"","sources":["../../../../src/config/settings/storageDrive.ts"],"names":[],"mappings":";;;AACA,4CAAqG;AACrG,gEAAiG;AAEjG;;GAEG;AACH,IAAY,gBAqDX;AArDD,WAAY,gBAAgB;IAC1B;;;OAGG;IACH,uCAAmB,CAAA;IAEnB;;;;;OAKG;IACH,2DAAuC,CAAA;IAEvC;;;;OAIG;IACH,mFAA+D,CAAA;IAE/D;;;;;OAKG;IACH,iDAA6B,CAAA;IAE7B;;;;;OAKG;IACH,+EAA2D,CAAA;IAE3D;;;;;OAKG;IACH,2DAAuC,CAAA;IAEvC;;;;;OAKG;IACH,mDAA+B,CAAA;AACjC,CAAC,EArDW,gBAAgB,gCAAhB,gBAAgB,QAqD3B;AAoEM,MAAM,kBAAkB,GAAG,CAAC,YAAoB,EAAE,OAA+C,EAAgC,EAAE;;IACxI,0EAA0E;IAC1E,sDAAsD;IACtD,IAAI,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,KAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,kBAAkB,YAAY,6CAA6C,CAAC,CAAC;IAC/F,CAAC;IAED,OAAO;QACL,iBAAiB,EAAE,oCAAwB,CAAC,YAAY;QACxD,SAAS,EAAE,YAAY;QAEvB,YAAY;QAEZ,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ;QAE3B,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAEhC,OAAO,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO;QAEzB,cAAc,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,cAAc;QAEvC,aAAa,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa;QACrC,MAAM,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,mCAAI,KAAK;QAChC,UAAU,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,UAAU,mCAAI,KAAK;QAExC,KAAK,EAAE,IAAA,uEAAoD,EAAC,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,CAAC;KAC5E,CAAC;AACJ,CAAC,CAAC;AA3BW,QAAA,kBAAkB,sBA2B7B","sourcesContent":["import { CrossModuleOwner, QpqFunctionRuntime } from '../../types';\nimport { QPQConfigAdvancedSettings, QPQConfigSetting, QPQCoreConfigSettingType } from '../QPQConfig';\nimport { convertCrossModuleOwnerToGenericResourceNameOverride } from '../utils/crossModuleUtils';\n\n/**\n * Represents different storage tiers for a \"storageDrive\".\n */\nexport enum StorageDriveTier {\n /**\n * Standard storage tier suitable for frequently accessed data.\n * (Reference: AWS S3 Standard)\n */\n REGULAR = 'REGULAR',\n\n /**\n * Storage tier optimized for data that is accessed less frequently,\n * but requires rapid access when needed. Lower availability compared\n * to the REGULAR tier.\n * (Reference: AWS S3 Infrequent Access)\n */\n OCCASIONAL_ACCESS = 'OCCASIONAL_ACCESS',\n\n /**\n * Optimized for infrequently accessed data stored in a single zone.\n * Lower availability compared to OCCASIONAL_ACCESS tier.\n * (Reference: AWS S3 One Zone-Infrequent Access)\n */\n SINGLE_ZONE_OCCASIONAL_ACCESS = 'SINGLE_ZONE_OCCASIONAL_ACCESS',\n\n /**\n * Cold storage tier suitable for long-term archival. Data retrieval\n * can take between minutes to hours. A cost-effective solution for\n * archival purposes where prompt data retrieval isn't crucial.\n * (Reference: AWS S3 Glacier)\n */\n COLD_STORAGE = 'COLD_STORAGE',\n\n /**\n * Cold storage tier optimized for long-term archival, but with the advantage\n * of immediate data access (in milliseconds). Ideal for data that might be\n * accessed once or twice per quarter.\n * (Reference: AWS S3 Glacier Instant Retrieval)\n */\n COLD_STORAGE_INSTANT_ACCESS = 'COLD_STORAGE_INSTANT_ACCESS',\n\n /**\n * Extremely cold storage suitable for data that's rarely accessed.\n * Data retrieval might take up to 12 hours. This offers the lowest\n * storage cost at the expense of retrieval time.\n * (Reference: AWS S3 Glacier Deep Archive)\n */\n DEEP_COLD_STORAGE = 'DEEP_COLD_STORAGE',\n\n /**\n * Dynamic storage tier designed to auto-optimize costs by moving data\n * between frequently and infrequently accessed tiers based on access patterns.\n * Ideal for long-lived data with unpredictable access patterns.\n * (Reference: AWS S3 Intelligent Tiering)\n */\n SMART_TIERING = 'SMART_TIERING',\n}\n\nexport type StorageDriveTransition = { storageDriveTier: StorageDriveTier } & (\n | {\n transitionAfterDays: number;\n transitionDate?: never;\n }\n | {\n transitionAfterDays?: never;\n transitionDate: string;\n }\n);\n\nexport type StorageDriveLifecycleRule = {\n prefix?: string;\n transitions?: StorageDriveTransition[];\n deleteAfterDays?: number;\n fileSizeLessThan?: number;\n fileSizeGreaterThan?: number;\n enabled?: boolean;\n\n // TODO: If we ever add versions\n // add noncurrentVersionExpiration / noncurrentVersionTransitions support\n};\n\nexport interface StorageDriveEvents {\n create?: QpqFunctionRuntime;\n delete?: QpqFunctionRuntime;\n}\n\nexport interface QPQConfigAdvancedStorageDriveSettings extends QPQConfigAdvancedSettings {\n copyPath?: string;\n global?: boolean;\n\n onEvent?: StorageDriveEvents;\n\n lifecycleRules?: StorageDriveLifecycleRule[];\n\n // Encrypt the drive with the named defineCryptoKey instead of the provider's own managed\n // encryption, which always applies. The key must be declared in the same config, owned or\n // foreign; a foreign key's owning service must be deployed first.\n cryptoKeyName?: string;\n\n // Every file action on this drive must carry a scope; an unscoped call is refused\n // rather than written to the bare path. Incompatible with copyPath.\n scoped?: boolean;\n\n // Only the owning service's runtime role may read objects. Every other principal in the\n // account, humans included, is denied at the bucket; writes and listing are unaffected.\n lockedDown?: boolean;\n\n owner?: CrossModuleOwner<'storageDriveName'>;\n}\n\nexport interface StorageDriveQPQConfigSetting extends QPQConfigSetting {\n storageDrive: string;\n copyPath?: string;\n global: boolean;\n\n onEvent?: StorageDriveEvents;\n\n lifecycleRules?: StorageDriveLifecycleRule[];\n\n cryptoKeyName?: string;\n scoped: boolean;\n lockedDown: boolean;\n}\n\nexport const defineStorageDrive = (storageDrive: string, options?: QPQConfigAdvancedStorageDriveSettings): StorageDriveQPQConfigSetting => {\n // copyPath content is deployed straight to the bucket root, outside every\n // scope, so it can never coexist with a scoped drive.\n if (options?.scoped && options.copyPath) {\n throw new Error(`Storage drive '${storageDrive}' cannot be both scoped and have a copyPath`);\n }\n\n return {\n configSettingType: QPQCoreConfigSettingType.storageDrive,\n uniqueKey: storageDrive,\n\n storageDrive,\n\n copyPath: options?.copyPath,\n\n global: options?.global ?? false,\n\n onEvent: options?.onEvent,\n\n lifecycleRules: options?.lifecycleRules,\n\n cryptoKeyName: options?.cryptoKeyName,\n scoped: options?.scoped ?? false,\n lockedDown: options?.lockedDown ?? false,\n\n owner: convertCrossModuleOwnerToGenericResourceNameOverride(options?.owner),\n };\n};\n"]}
|
|
@@ -18,6 +18,7 @@ __exportStar(require("./actionValidators"), exports);
|
|
|
18
18
|
__exportStar(require("./context"), exports);
|
|
19
19
|
__exportStar(require("./decomposedString"), exports);
|
|
20
20
|
__exportStar(require("./error"), exports);
|
|
21
|
+
__exportStar(require("./keyValueStore"), exports);
|
|
21
22
|
__exportStar(require("./logHistory"), exports);
|
|
22
23
|
__exportStar(require("./lookup"), exports);
|
|
23
24
|
__exportStar(require("./scope"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/logic/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,4CAA0B;AAC1B,qDAAmC;AACnC,0CAAwB;AACxB,+CAA6B;AAC7B,2CAAyB;AACzB,0CAAwB;AACxB,iDAA+B;AAC/B,2CAAyB;AACzB,wDAAsC","sourcesContent":["export * from './actionValidators';\nexport * from './context';\nexport * from './decomposedString';\nexport * from './error';\nexport * from './logHistory';\nexport * from './lookup';\nexport * from './scope';\nexport * from './stateEffects';\nexport * from './stream';\nexport * from './transientErrorNames';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/logic/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,4CAA0B;AAC1B,qDAAmC;AACnC,0CAAwB;AACxB,kDAAgC;AAChC,+CAA6B;AAC7B,2CAAyB;AACzB,0CAAwB;AACxB,iDAA+B;AAC/B,2CAAyB;AACzB,wDAAsC","sourcesContent":["export * from './actionValidators';\nexport * from './context';\nexport * from './decomposedString';\nexport * from './error';\nexport * from './keyValueStore';\nexport * from './logHistory';\nexport * from './lookup';\nexport * from './scope';\nexport * from './stateEffects';\nexport * from './stream';\nexport * from './transientErrorNames';\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** A query named an index its store doesn't declare. Query processors map it to the action's IndexNotFound. */
|
|
2
|
+
export declare class KvsIndexNotFoundError extends Error {
|
|
3
|
+
readonly code = "KvsIndexNotFoundError";
|
|
4
|
+
constructor(keyValueStoreName: string, indexName: string);
|
|
5
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KvsIndexNotFoundError = void 0;
|
|
4
|
+
/** A query named an index its store doesn't declare. Query processors map it to the action's IndexNotFound. */
|
|
5
|
+
class KvsIndexNotFoundError extends Error {
|
|
6
|
+
constructor(keyValueStoreName, indexName) {
|
|
7
|
+
super(`Key value store '${keyValueStoreName}' has no index named '${indexName}'`);
|
|
8
|
+
this.code = 'KvsIndexNotFoundError';
|
|
9
|
+
this.name = 'KvsIndexNotFoundError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.KvsIndexNotFoundError = KvsIndexNotFoundError;
|
|
13
|
+
//# sourceMappingURL=KvsIndexNotFoundError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KvsIndexNotFoundError.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/KvsIndexNotFoundError.ts"],"names":[],"mappings":";;;AAAA,+GAA+G;AAC/G,MAAa,qBAAsB,SAAQ,KAAK;IAG9C,YAAY,iBAAyB,EAAE,SAAiB;QACtD,KAAK,CAAC,oBAAoB,iBAAiB,yBAAyB,SAAS,GAAG,CAAC,CAAC;QAH3E,SAAI,GAAG,uBAAuB,CAAC;QAItC,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAPD,sDAOC","sourcesContent":["/** A query named an index its store doesn't declare. Query processors map it to the action's IndexNotFound. */\nexport class KvsIndexNotFoundError extends Error {\n readonly code = 'KvsIndexNotFoundError';\n\n constructor(keyValueStoreName: string, indexName: string) {\n super(`Key value store '${keyValueStoreName}' has no index named '${indexName}'`);\n this.name = 'KvsIndexNotFoundError';\n }\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { KvsQueryCondition, KvsQueryOperation } from '../../actions/keyValueStore/types';
|
|
2
|
+
/** Flatten a query tree into its leaf conditions, in traversal order. Malformed nodes are dropped. */
|
|
3
|
+
export declare const flattenKvsQueryConditions: (operation: KvsQueryOperation) => KvsQueryCondition[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flattenKvsQueryConditions = void 0;
|
|
4
|
+
/** Flatten a query tree into its leaf conditions, in traversal order. Malformed nodes are dropped. */
|
|
5
|
+
const flattenKvsQueryConditions = (operation) => {
|
|
6
|
+
if ('key' in operation && 'operation' in operation) {
|
|
7
|
+
return [operation];
|
|
8
|
+
}
|
|
9
|
+
if ('conditions' in operation && 'operation' in operation) {
|
|
10
|
+
return operation.conditions.flatMap(exports.flattenKvsQueryConditions);
|
|
11
|
+
}
|
|
12
|
+
return [];
|
|
13
|
+
};
|
|
14
|
+
exports.flattenKvsQueryConditions = flattenKvsQueryConditions;
|
|
15
|
+
//# sourceMappingURL=flattenKvsQueryConditions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenKvsQueryConditions.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/flattenKvsQueryConditions.ts"],"names":[],"mappings":";;;AAEA,sGAAsG;AAC/F,MAAM,yBAAyB,GAAG,CAAC,SAA4B,EAAuB,EAAE;IAC7F,IAAI,KAAK,IAAI,SAAS,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;QACnD,OAAO,CAAC,SAAS,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,YAAY,IAAI,SAAS,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;QAC1D,OAAO,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,iCAAyB,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAVW,QAAA,yBAAyB,6BAUpC","sourcesContent":["import { KvsQueryCondition, KvsQueryOperation } from '../../actions/keyValueStore/types';\n\n/** Flatten a query tree into its leaf conditions, in traversal order. Malformed nodes are dropped. */\nexport const flattenKvsQueryConditions = (operation: KvsQueryOperation): KvsQueryCondition[] => {\n if ('key' in operation && 'operation' in operation) {\n return [operation];\n }\n\n if ('conditions' in operation && 'operation' in operation) {\n return operation.conditions.flatMap(flattenKvsQueryConditions);\n }\n\n return [];\n};\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./flattenKvsQueryConditions"), exports);
|
|
18
|
+
__exportStar(require("./KvsIndexNotFoundError"), exports);
|
|
19
|
+
__exportStar(require("./resolveKvsQueryIndex"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8DAA4C;AAC5C,0DAAwC;AACxC,yDAAuC","sourcesContent":["export * from './flattenKvsQueryConditions';\nexport * from './KvsIndexNotFoundError';\nexport * from './resolveKvsQueryIndex';\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { KvsQueryOperation } from '../../actions/keyValueStore/types';
|
|
2
|
+
import { KeyValueStoreQPQConfigSetting, KvsIndex } from '../../config/settings/keyValueStore';
|
|
3
|
+
import { Nullable } from '../../types/Nullable';
|
|
4
|
+
/**
|
|
5
|
+
* The index a query runs against, or null for the table itself. `name` forces the declared index with
|
|
6
|
+
* that name; an undeclared name throws KvsIndexNotFoundError. Otherwise the first of the table, then each
|
|
7
|
+
* index in declaration order, whose keys cover every attribute the key condition names; the table wins
|
|
8
|
+
* ties (it can serve consistent reads). Null when nothing covers it, so the table refuses the query.
|
|
9
|
+
*/
|
|
10
|
+
export declare const resolveKvsQueryIndex: (storeConfig: KeyValueStoreQPQConfigSetting, keyCondition: KvsQueryOperation, name?: string) => Nullable<KvsIndex>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveKvsQueryIndex = void 0;
|
|
4
|
+
const flattenKvsQueryConditions_1 = require("./flattenKvsQueryConditions");
|
|
5
|
+
const KvsIndexNotFoundError_1 = require("./KvsIndexNotFoundError");
|
|
6
|
+
// A key condition may only name the partition key and sort key of whatever it runs against, and must
|
|
7
|
+
// name the partition key.
|
|
8
|
+
const keySchemaServes = (queriedKeys, partitionKey, sortKey) => queriedKeys.includes(partitionKey.key) && queriedKeys.every((key) => key === partitionKey.key || key === (sortKey === null || sortKey === void 0 ? void 0 : sortKey.key));
|
|
9
|
+
/**
|
|
10
|
+
* The index a query runs against, or null for the table itself. `name` forces the declared index with
|
|
11
|
+
* that name; an undeclared name throws KvsIndexNotFoundError. Otherwise the first of the table, then each
|
|
12
|
+
* index in declaration order, whose keys cover every attribute the key condition names; the table wins
|
|
13
|
+
* ties (it can serve consistent reads). Null when nothing covers it, so the table refuses the query.
|
|
14
|
+
*/
|
|
15
|
+
const resolveKvsQueryIndex = (storeConfig, keyCondition, name) => {
|
|
16
|
+
var _a;
|
|
17
|
+
if (name !== undefined) {
|
|
18
|
+
const namedIndex = storeConfig.indexes.find((index) => index.name === name);
|
|
19
|
+
if (!namedIndex) {
|
|
20
|
+
throw new KvsIndexNotFoundError_1.KvsIndexNotFoundError(storeConfig.keyValueStoreName, name);
|
|
21
|
+
}
|
|
22
|
+
return namedIndex;
|
|
23
|
+
}
|
|
24
|
+
const queriedKeys = (0, flattenKvsQueryConditions_1.flattenKvsQueryConditions)(keyCondition).map((condition) => condition.key);
|
|
25
|
+
if (keySchemaServes(queriedKeys, storeConfig.partitionKey, storeConfig.sortKeys[0])) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return (_a = storeConfig.indexes.find((index) => keySchemaServes(queriedKeys, index.partitionKey, index.sortKey))) !== null && _a !== void 0 ? _a : null;
|
|
29
|
+
};
|
|
30
|
+
exports.resolveKvsQueryIndex = resolveKvsQueryIndex;
|
|
31
|
+
//# sourceMappingURL=resolveKvsQueryIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveKvsQueryIndex.js","sourceRoot":"","sources":["../../../../src/logic/keyValueStore/resolveKvsQueryIndex.ts"],"names":[],"mappings":";;;AAGA,2EAAwE;AACxE,mEAAgE;AAEhE,qGAAqG;AACrG,0BAA0B;AAC1B,MAAM,eAAe,GAAG,CAAC,WAAqB,EAAE,YAAoB,EAAE,OAAgB,EAAW,EAAE,CACjG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,YAAY,CAAC,GAAG,IAAI,GAAG,MAAK,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,GAAG,CAAA,CAAC,CAAC;AAEzH;;;;;GAKG;AACI,MAAM,oBAAoB,GAAG,CAClC,WAA0C,EAC1C,YAA+B,EAC/B,IAAa,EACO,EAAE;;IACtB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAC5E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,6CAAqB,CAAC,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,WAAW,GAAG,IAAA,qDAAyB,EAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9F,IAAI,eAAe,CAAC,WAAW,EAAE,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAA,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,mCAAI,IAAI,CAAC;AACtH,CAAC,CAAC;AApBW,QAAA,oBAAoB,wBAoB/B","sourcesContent":["import { KvsQueryOperation } from '../../actions/keyValueStore/types';\nimport { KeyValueStoreQPQConfigSetting, KvsIndex, KvsKey } from '../../config/settings/keyValueStore';\nimport { Nullable } from '../../types/Nullable';\nimport { flattenKvsQueryConditions } from './flattenKvsQueryConditions';\nimport { KvsIndexNotFoundError } from './KvsIndexNotFoundError';\n\n// A key condition may only name the partition key and sort key of whatever it runs against, and must\n// name the partition key.\nconst keySchemaServes = (queriedKeys: string[], partitionKey: KvsKey, sortKey?: KvsKey): boolean =>\n queriedKeys.includes(partitionKey.key) && queriedKeys.every((key) => key === partitionKey.key || key === sortKey?.key);\n\n/**\n * The index a query runs against, or null for the table itself. `name` forces the declared index with\n * that name; an undeclared name throws KvsIndexNotFoundError. Otherwise the first of the table, then each\n * index in declaration order, whose keys cover every attribute the key condition names; the table wins\n * ties (it can serve consistent reads). Null when nothing covers it, so the table refuses the query.\n */\nexport const resolveKvsQueryIndex = (\n storeConfig: KeyValueStoreQPQConfigSetting,\n keyCondition: KvsQueryOperation,\n name?: string,\n): Nullable<KvsIndex> => {\n if (name !== undefined) {\n const namedIndex = storeConfig.indexes.find((index) => index.name === name);\n if (!namedIndex) {\n throw new KvsIndexNotFoundError(storeConfig.keyValueStoreName, name);\n }\n\n return namedIndex;\n }\n\n const queriedKeys = flattenKvsQueryConditions(keyCondition).map((condition) => condition.key);\n if (keySchemaServes(queriedKeys, storeConfig.partitionKey, storeConfig.sortKeys[0])) {\n return null;\n }\n\n return storeConfig.indexes.find((index) => keySchemaServes(queriedKeys, index.partitionKey, index.sortKey)) ?? null;\n};\n"]}
|
|
@@ -4,7 +4,13 @@ export declare enum InvalidScopeErrorCode {
|
|
|
4
4
|
tooLong = "tooLong",
|
|
5
5
|
unsafePath = "unsafePath",
|
|
6
6
|
queryMissingPartitionKey = "queryMissingPartitionKey",
|
|
7
|
-
reservedDelimiter = "reservedDelimiter"
|
|
7
|
+
reservedDelimiter = "reservedDelimiter",
|
|
8
|
+
scopeRequired = "scopeRequired",
|
|
9
|
+
notScoped = "notScoped",
|
|
10
|
+
reservedAttribute = "reservedAttribute",
|
|
11
|
+
indexKeyType = "indexKeyType",
|
|
12
|
+
unsupportedOperation = "unsupportedOperation",
|
|
13
|
+
pageKeyOutOfScope = "pageKeyOutOfScope"
|
|
8
14
|
}
|
|
9
15
|
export declare class InvalidScopeError extends Error {
|
|
10
16
|
readonly code: InvalidScopeErrorCode;
|
|
@@ -23,6 +23,28 @@ var InvalidScopeErrorCode;
|
|
|
23
23
|
// A raw partition-key value containing the scope delimiter: storing it would
|
|
24
24
|
// make the row indistinguishable from another scope's composed data.
|
|
25
25
|
InvalidScopeErrorCode["reservedDelimiter"] = "reservedDelimiter";
|
|
26
|
+
// The resource is declared `scoped` in config but the call carried no scope.
|
|
27
|
+
// On a drive that would land the object beside every tenant's prefix; on a
|
|
28
|
+
// store it would read or write the unpartitioned rows.
|
|
29
|
+
InvalidScopeErrorCode["scopeRequired"] = "scopeRequired";
|
|
30
|
+
// The call carried a scope but the resource is not declared `scoped` in
|
|
31
|
+
// config: the data would land under a prefix nothing else on that resource
|
|
32
|
+
// expects, invisible to every unscoped reader.
|
|
33
|
+
InvalidScopeErrorCode["notScoped"] = "notScoped";
|
|
34
|
+
// An attribute name on a scoped store carrying the reserved marker. Those
|
|
35
|
+
// attributes belong to the backend (its own index bookkeeping); a caller-set
|
|
36
|
+
// one could file the row under another scope's index partition.
|
|
37
|
+
InvalidScopeErrorCode["reservedAttribute"] = "reservedAttribute";
|
|
38
|
+
// A scoped store's index partition key value that doesn't match the key's
|
|
39
|
+
// declared type.
|
|
40
|
+
InvalidScopeErrorCode["indexKeyType"] = "indexKeyType";
|
|
41
|
+
// Something a scoped store's index partition key can't support: a non-equality
|
|
42
|
+
// key condition on it, or an update whose result isn't known up front
|
|
43
|
+
// (Increment, Add, Delete, a nested path).
|
|
44
|
+
InvalidScopeErrorCode["unsupportedOperation"] = "unsupportedOperation";
|
|
45
|
+
// A page key issued under another scope. A page key only continues the
|
|
46
|
+
// listing that issued it; one edited to point elsewhere is refused.
|
|
47
|
+
InvalidScopeErrorCode["pageKeyOutOfScope"] = "pageKeyOutOfScope";
|
|
26
48
|
})(InvalidScopeErrorCode || (exports.InvalidScopeErrorCode = InvalidScopeErrorCode = {}));
|
|
27
49
|
class InvalidScopeError extends Error {
|
|
28
50
|
constructor(code, message) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvalidScopeError.js","sourceRoot":"","sources":["../../../../src/logic/scope/InvalidScopeError.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AACvE,6EAA6E;AAC7E,mBAAmB;AACnB,IAAY,
|
|
1
|
+
{"version":3,"file":"InvalidScopeError.js","sourceRoot":"","sources":["../../../../src/logic/scope/InvalidScopeError.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AACvE,6EAA6E;AAC7E,mBAAmB;AACnB,IAAY,qBAsCX;AAtCD,WAAY,qBAAqB;IAC/B,kCAAkC;IAClC,wCAAe,CAAA;IACf,mDAAmD;IACnD,8DAAqC,CAAA;IACrC,kEAAkE;IAClE,4CAAmB,CAAA;IACnB,uEAAuE;IACvE,yCAAyC;IACzC,kDAAyB,CAAA;IACzB,0EAA0E;IAC1E,0EAA0E;IAC1E,8EAAqD,CAAA;IACrD,6EAA6E;IAC7E,qEAAqE;IACrE,gEAAuC,CAAA;IACvC,6EAA6E;IAC7E,2EAA2E;IAC3E,uDAAuD;IACvD,wDAA+B,CAAA;IAC/B,wEAAwE;IACxE,2EAA2E;IAC3E,+CAA+C;IAC/C,gDAAuB,CAAA;IACvB,0EAA0E;IAC1E,6EAA6E;IAC7E,gEAAgE;IAChE,gEAAuC,CAAA;IACvC,0EAA0E;IAC1E,iBAAiB;IACjB,sDAA6B,CAAA;IAC7B,+EAA+E;IAC/E,sEAAsE;IACtE,2CAA2C;IAC3C,sEAA6C,CAAA;IAC7C,uEAAuE;IACvE,oEAAoE;IACpE,gEAAuC,CAAA;AACzC,CAAC,EAtCW,qBAAqB,qCAArB,qBAAqB,QAsChC;AAED,MAAa,iBAAkB,SAAQ,KAAK;IAC1C,YACkB,IAA2B,EAC3C,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,SAAI,GAAJ,IAAI,CAAuB;QAI3C,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AARD,8CAQC","sourcesContent":["// Raised when a scope segment fails validation. Scope is an opaque identifier\n// (supplied by a higher-level data-partitioning feature) that gets embedded\n// into file paths and kvs partition keys, so a malformed one is always\n// rejected outright - never normalized - to make escaping a scope impossible\n// by construction.\nexport enum InvalidScopeErrorCode {\n // Empty or whitespace-only scope.\n empty = 'empty',\n // Contains a path separator, '..', or a null byte.\n unsafeCharacters = 'unsafeCharacters',\n // Longer than the allowed maximum (scopes are ids, not payloads).\n tooLong = 'tooLong',\n // A filepath composed under a scope could traverse out of it (absolute\n // path, a '..' segment, or a null byte).\n unsafePath = 'unsafePath',\n // A scoped query whose key condition never constrains the partition key -\n // on value-composed backends (dynamo) it would silently span every scope.\n queryMissingPartitionKey = 'queryMissingPartitionKey',\n // A raw partition-key value containing the scope delimiter: storing it would\n // make the row indistinguishable from another scope's composed data.\n reservedDelimiter = 'reservedDelimiter',\n // The resource is declared `scoped` in config but the call carried no scope.\n // On a drive that would land the object beside every tenant's prefix; on a\n // store it would read or write the unpartitioned rows.\n scopeRequired = 'scopeRequired',\n // The call carried a scope but the resource is not declared `scoped` in\n // config: the data would land under a prefix nothing else on that resource\n // expects, invisible to every unscoped reader.\n notScoped = 'notScoped',\n // An attribute name on a scoped store carrying the reserved marker. Those\n // attributes belong to the backend (its own index bookkeeping); a caller-set\n // one could file the row under another scope's index partition.\n reservedAttribute = 'reservedAttribute',\n // A scoped store's index partition key value that doesn't match the key's\n // declared type.\n indexKeyType = 'indexKeyType',\n // Something a scoped store's index partition key can't support: a non-equality\n // key condition on it, or an update whose result isn't known up front\n // (Increment, Add, Delete, a nested path).\n unsupportedOperation = 'unsupportedOperation',\n // A page key issued under another scope. A page key only continues the\n // listing that issued it; one edited to point elsewhere is refused.\n pageKeyOutOfScope = 'pageKeyOutOfScope',\n}\n\nexport class InvalidScopeError extends Error {\n constructor(\n public readonly code: InvalidScopeErrorCode,\n message: string,\n ) {\n super(message);\n this.name = 'InvalidScopeError';\n }\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { QPQConfig } from '../../config';
|
|
2
|
+
export declare const assertStorageDriveScopeRequirementOrThrow: (qpqConfig: QPQConfig, drive: string, scope: string | undefined) => void;
|
|
3
|
+
/**
|
|
4
|
+
* Gate then compose: the path a key-based backend (s3) stores under. Throws
|
|
5
|
+
* InvalidScopeError when the drive is scoped and no scope was given, or when
|
|
6
|
+
* the scope or filepath fails validation.
|
|
7
|
+
*/
|
|
8
|
+
export declare const composeStorageDriveFilePathOrThrow: (qpqConfig: QPQConfig, drive: string, scope: string | undefined, filepath: string) => string;
|