diff --git a/docs/docs/04-standard-library/compatibility/compatibility.json b/docs/docs/04-standard-library/compatibility/compatibility.json index 96705788548..f33fb1ec3cf 100644 --- a/docs/docs/04-standard-library/compatibility/compatibility.json +++ b/docs/docs/04-standard-library/compatibility/compatibility.json @@ -297,35 +297,35 @@ "sim": { "implemented": true }, "tf-aws": { "implemented": true }, "tf-azure": { "implemented": false, "issue": 629 }, - "tf-gcp": { "implemented": false, "issue": 628 }, + "tf-gcp": { "implemented": true }, "awscdk": { "implemented": true } }, "inc": { "sim": { "implemented": true }, "tf-aws": { "implemented": true }, "tf-azure": { "implemented": false, "issue": 629 }, - "tf-gcp": { "implemented": false, "issue": 628 }, + "tf-gcp": { "implemented": true }, "awscdk": { "implemented": true } }, "dec": { "sim": { "implemented": true }, "tf-aws": { "implemented": true }, "tf-azure": { "implemented": false, "issue": 629 }, - "tf-gcp": { "implemented": false, "issue": 628 }, + "tf-gcp": { "implemented": true }, "awscdk": { "implemented": true } }, "peek": { "sim": { "implemented": true }, "tf-aws": { "implemented": true }, "tf-azure": { "implemented": false, "issue": 629 }, - "tf-gcp": { "implemented": false, "issue": 628 }, + "tf-gcp": { "implemented": true }, "awscdk": { "implemented": true } }, - "reset": { + "set": { "sim": { "implemented": true }, "tf-aws": { "implemented": true }, "tf-azure": { "implemented": false, "issue": 629 }, - "tf-gcp": { "implemented": false, "issue": 628 }, + "tf-gcp": { "implemented": true }, "awscdk": { "implemented": true } } }, diff --git a/examples/tests/sdk_tests/counter/dec.test.w b/examples/tests/sdk_tests/counter/dec.test.w index 23adf176eff..59fdd86f29a 100644 --- a/examples/tests/sdk_tests/counter/dec.test.w +++ b/examples/tests/sdk_tests/counter/dec.test.w @@ -1,24 +1,48 @@ bring cloud; +bring expect; -let counter = new cloud.Counter(initial: 1); +// implicit initial (0) +let counter1 = new cloud.Counter() as "counter1"; +// explicit initial +let counter2 = new cloud.Counter(initial: -1) as "counter2"; -test "dec" { - assert(counter.peek() == 1); - let dec1 = counter.dec(); - assert(counter.peek() == 0); - assert(dec1 == 1); - let dec2 = counter.dec(2); - assert(counter.peek() == -2); - assert(dec2 == 0); +test "dec()" { + // implicit decrement (-1) + let r0 = counter1.dec(); + expect.equal(r0, 0); + expect.equal(counter1.peek(), -1); + + // explicit decrement (positive int) + let r1 = counter1.dec(5); + expect.equal(r1, -1); + expect.equal(counter1.peek(), -6); + + // explicit decrement (negative int) + let r2 = counter1.dec(-4); + expect.equal(r2, -6); + expect.equal(counter1.peek(), -2); + + // explicit decrement (-0) + let r3 = counter1.dec(0); + expect.equal(r3, -2); + expect.equal(counter1.peek(), -2); } -test "key dec" { - let key = "my-key"; - assert(counter.peek(key) == 1); - let dec1 = counter.dec(nil, key); - assert(counter.peek(key) == 0); - assert(dec1 == 1); - let dec2 = counter.dec(2, key); - assert(counter.peek(key) == -2); - assert(dec2 == 0); +test "dec() with custom key" { + let key = "custom-key"; + + // explicit decrement (positive int) + let r1 = counter2.dec(5, key); + expect.equal(r1, -1); + expect.equal(counter2.peek(key), -6); + + // explicit decrement (negative int) + let r2 = counter2.dec(-4, key); + expect.equal(r2, -6); + expect.equal(counter2.peek(key), -2); + + // explicit decrement (-0) + let r3 = counter2.dec(0, key); + expect.equal(r3, -2); + expect.equal(counter2.peek(key), -2); } diff --git a/examples/tests/sdk_tests/counter/inc.test.w b/examples/tests/sdk_tests/counter/inc.test.w index 6c2165be39e..ce7b0d015fb 100644 --- a/examples/tests/sdk_tests/counter/inc.test.w +++ b/examples/tests/sdk_tests/counter/inc.test.w @@ -1,34 +1,48 @@ bring cloud; +bring expect; -let counter = new cloud.Counter(initial: 0); - -test "inc" { - assert(counter.peek() == 0); - let r0 = counter.inc(); - assert(r0 == 0); - assert(counter.peek() == 1); - let r1 = counter.inc(); - assert(r1 == 1); - assert(counter.peek() == 2); - let r2 = counter.inc(10); - assert(r2 == 2); - assert(counter.peek() == 12); - let r3 = counter.inc(); - assert(r3 == 12); +// implicit initial (0) +let counter1 = new cloud.Counter() as "counter1"; +// explicit initial +let counter2 = new cloud.Counter(initial: -1) as "counter2"; + +test "inc()" { + // implicit increment (+1) + let r0 = counter1.inc(); + expect.equal(r0, 0); + expect.equal(counter1.peek(), 1); + + // explicit increment (positive int) + let r1 = counter1.inc(5); + expect.equal(r1, 1); + expect.equal(counter1.peek(), 6); + + // explicit increment (negative int) + let r2 = counter1.inc(-4); + expect.equal(r2, 6); + expect.equal(counter1.peek(), 2); + + // explicit increment (+0) + let r3 = counter1.inc(0); + expect.equal(r3, 2); + expect.equal(counter1.peek(), 2); } -test "key inc" { - let key = "my-key"; - assert(counter.peek(key) == 0); - let r0 = counter.inc(nil, key); - assert(r0 == 0); - assert(counter.peek(key) == 1); - let r1 = counter.inc(nil, key); - assert(r1 == 1); - assert(counter.peek(key) == 2); - let r2 = counter.inc(10, key); - assert(r2 == 2); - assert(counter.peek(key) == 12); - let r3 = counter.inc(nil, key); - assert(r3 == 12); +test "inc() with custom key" { + let key = "custom-key"; + + // explicit increment (positive int) + let r1 = counter2.inc(5, key); + expect.equal(r1, -1); + expect.equal(counter2.peek(key), 4); + + // explicit increment (negative int) + let r2 = counter2.inc(-4, key); + expect.equal(r2, 4); + expect.equal(counter2.peek(key), 0); + + // explicit increment (+0) + let r3 = counter2.inc(0, key); + expect.equal(r3, 0); + expect.equal(counter2.peek(key), 0); } diff --git a/examples/tests/sdk_tests/counter/initial.test.w b/examples/tests/sdk_tests/counter/initial.test.w index 8f7bd0d0e35..0743217c625 100644 --- a/examples/tests/sdk_tests/counter/initial.test.w +++ b/examples/tests/sdk_tests/counter/initial.test.w @@ -1,17 +1,18 @@ bring cloud; +bring expect; let counterA = new cloud.Counter() as "counterA"; let counterB = new cloud.Counter(initial: 500) as "counterB"; let counterC = new cloud.Counter(initial: -198) as "counterC"; test "initial:default" { - assert(counterA.peek() == 0); + expect.equal(counterA.peek(), 0); } test "initial:positive-value" { - assert(counterB.peek() == 500); + expect.equal(counterB.peek(), 500); } test "initial:negative-value" { - assert(counterC.peek() == -198); + expect.equal(counterC.peek(), -198); } diff --git a/examples/tests/sdk_tests/counter/peek.test.w b/examples/tests/sdk_tests/counter/peek.test.w index f6a97356ff0..630d1f8a077 100644 --- a/examples/tests/sdk_tests/counter/peek.test.w +++ b/examples/tests/sdk_tests/counter/peek.test.w @@ -1,18 +1,19 @@ bring cloud; +bring expect; let c = new cloud.Counter(); test "peek" { - assert(c.peek() == 0); - assert(c.peek() == 0); + expect.equal(c.peek(), 0); + expect.equal(c.peek(), 0); c.inc(); - assert(c.peek() == 1); + expect.equal(c.peek(), 1); } test "key peek" { let key = "my-key"; - assert(c.peek(key) == 0); - assert(c.peek(key) == 0); + expect.equal(c.peek(key), 0); + expect.equal(c.peek(key), 0); c.inc(nil, key); - assert(c.peek(key) == 1); + expect.equal(c.peek(key), 1); } \ No newline at end of file diff --git a/examples/tests/sdk_tests/counter/set.test.w b/examples/tests/sdk_tests/counter/set.test.w index 851d34b079a..bf48b222263 100644 --- a/examples/tests/sdk_tests/counter/set.test.w +++ b/examples/tests/sdk_tests/counter/set.test.w @@ -1,28 +1,37 @@ bring cloud; +bring expect; -let counter = new cloud.Counter(initial: 0); - -test "set" { - assert(counter.peek() == 0); - counter.inc(); - assert(counter.peek() == 1); - counter.inc(); - assert(counter.peek() == 2); - counter.inc(10); - assert(counter.peek() == 12); - counter.set(88); - assert(counter.peek() == 88); +// implicit initial (0) +let counter1 = new cloud.Counter() as "counter1"; +// explicit initial +let counter2 = new cloud.Counter(initial: -1) as "counter2"; + +test "set()" { + // set (positive int) + counter1.set(42); + expect.equal(counter1.peek(), 42); + + // set (negative int) + counter1.set(-100); + expect.equal(counter1.peek(), -100); + + // set (0) + counter1.set(0); + expect.equal(counter1.peek(), 0); } -test "key set" { - let key = "my-key"; - assert(counter.peek(key) == 0); - counter.inc(nil, key); - assert(counter.peek(key) == 1); - counter.inc(nil, key); - assert(counter.peek(key) == 2); - counter.inc(10, key); - assert(counter.peek(key) == 12); - counter.set(88, key); - assert(counter.peek(key) == 88); -} \ No newline at end of file +test "set() with custom key" { + let key = "custom-key"; + + // set (positive int) + counter2.set(42, key); + expect.equal(counter2.peek(key), 42); + + // set (negative int) + counter2.set(-100, key); + expect.equal(counter2.peek(key), -100); + + // set (0) + counter2.set(0, key); + expect.equal(counter2.peek(key), 0); +} diff --git a/libs/wingsdk/.projen/deps.json b/libs/wingsdk/.projen/deps.json index 9df67787c93..5d15c001346 100644 --- a/libs/wingsdk/.projen/deps.json +++ b/libs/wingsdk/.projen/deps.json @@ -234,6 +234,11 @@ "version": "12.14.0", "type": "bundled" }, + { + "name": "@google-cloud/datastore", + "version": "8.4.0", + "type": "bundled" + }, { "name": "@google-cloud/storage", "version": "6.9.5", @@ -296,6 +301,11 @@ "version": "^3.3.6", "type": "bundled" }, + { + "name": "protobufjs", + "version": "7.2.5", + "type": "bundled" + }, { "name": "safe-stable-stringify", "type": "bundled" diff --git a/libs/wingsdk/.projen/tasks.json b/libs/wingsdk/.projen/tasks.json index 3dbf87598c7..327b3fed5d2 100644 --- a/libs/wingsdk/.projen/tasks.json +++ b/libs/wingsdk/.projen/tasks.json @@ -630,25 +630,25 @@ "exec": "pnpm update npm-check-updates" }, { - "exec": "npm-check-updates --dep dev --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf'" + "exec": "npm-check-updates --dep dev --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/datastore,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf,protobufjs'" }, { - "exec": "npm-check-updates --dep bundle --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf'" + "exec": "npm-check-updates --dep bundle --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/datastore,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf,protobufjs'" }, { - "exec": "npm-check-updates --dep peer --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf'" + "exec": "npm-check-updates --dep peer --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/datastore,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf,protobufjs'" }, { - "exec": "npm-check-updates --dep prod --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf'" + "exec": "npm-check-updates --dep prod --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/datastore,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf,protobufjs'" }, { - "exec": "npm-check-updates --dep optional --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf'" + "exec": "npm-check-updates --dep optional --upgrade --target=minor --reject='aws-sdk-client-mock-jest,aws-sdk-client-mock,cdktf-cli,constructs,jsii,@aws-sdk/client-cloudwatch-logs,@aws-sdk/client-dynamodb,@aws-sdk/client-elasticache,@aws-sdk/client-lambda,@aws-sdk/client-s3,@aws-sdk/client-secrets-manager,@aws-sdk/client-sns,@aws-sdk/client-sqs,@aws-sdk/s3-request-presigner,@aws-sdk/types,@aws-sdk/util-dynamodb,@azure/identity,@azure/storage-blob,@google-cloud/datastore,@google-cloud/storage,@smithy/util-stream,@smithy/util-utf8,cdktf,protobufjs'" }, { "exec": "pnpm i --no-frozen-lockfile" }, { - "exec": "pnpm update @cdktf/provider-aws @types/aws-lambda @types/express @types/fs-extra @types/mime-types @types/node @types/uuid @typescript-eslint/eslint-plugin @typescript-eslint/parser @vitest/coverage-v8 @winglang/jsii-docgen aws-sdk-client-mock-jest aws-sdk-client-mock bump-pack cdktf-cli chalk constructs eslint-config-prettier eslint-import-resolver-node eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-prettier eslint-plugin-sort-exports eslint fs-extra jsii-diff jsii-pacmak jsii mock-gcs nanoid npm-check-updates prettier projen standard-version ts-node typescript vitest wing-api-checker @aws-sdk/client-cloudwatch-logs @aws-sdk/client-dynamodb @aws-sdk/client-elasticache @aws-sdk/client-lambda @aws-sdk/client-s3 @aws-sdk/client-secrets-manager @aws-sdk/client-sns @aws-sdk/client-sqs @aws-sdk/s3-request-presigner @aws-sdk/types @aws-sdk/util-dynamodb @azure/core-paging @azure/identity @azure/storage-blob @google-cloud/storage @smithy/util-stream @smithy/util-utf8 @types/aws-lambda cdktf cron-parser esbuild-wasm express google-auth-library ioredis jsonschema mime-types mime nanoid safe-stable-stringify stacktracey ulid undici uuid yaml @types/node constructs constructs" + "exec": "pnpm update @cdktf/provider-aws @types/aws-lambda @types/express @types/fs-extra @types/mime-types @types/node @types/uuid @typescript-eslint/eslint-plugin @typescript-eslint/parser @vitest/coverage-v8 @winglang/jsii-docgen aws-sdk-client-mock-jest aws-sdk-client-mock bump-pack cdktf-cli chalk constructs eslint-config-prettier eslint-import-resolver-node eslint-import-resolver-typescript eslint-plugin-import eslint-plugin-prettier eslint-plugin-sort-exports eslint fs-extra jsii-diff jsii-pacmak jsii mock-gcs nanoid npm-check-updates prettier projen standard-version ts-node typescript vitest wing-api-checker @aws-sdk/client-cloudwatch-logs @aws-sdk/client-dynamodb @aws-sdk/client-elasticache @aws-sdk/client-lambda @aws-sdk/client-s3 @aws-sdk/client-secrets-manager @aws-sdk/client-sns @aws-sdk/client-sqs @aws-sdk/s3-request-presigner @aws-sdk/types @aws-sdk/util-dynamodb @azure/core-paging @azure/identity @azure/storage-blob @google-cloud/datastore @google-cloud/storage @smithy/util-stream @smithy/util-utf8 @types/aws-lambda cdktf cron-parser esbuild-wasm express google-auth-library ioredis jsonschema mime-types mime nanoid protobufjs safe-stable-stringify stacktracey ulid undici uuid yaml @types/node constructs constructs" }, { "exec": "pnpm exec projen" diff --git a/libs/wingsdk/.projenrc.ts b/libs/wingsdk/.projenrc.ts index 599fc9e84ed..b40986fcddb 100644 --- a/libs/wingsdk/.projenrc.ts +++ b/libs/wingsdk/.projenrc.ts @@ -88,7 +88,9 @@ const project = new cdk.JsiiProject({ "@azure/core-paging", // gcp client dependencies "@google-cloud/storage@6.9.5", + "@google-cloud/datastore@8.4.0", "google-auth-library", + "protobufjs@7.2.5", // simulator dependencies "express", "uuid", diff --git a/libs/wingsdk/package.json b/libs/wingsdk/package.json index 9f6ad1ac277..292012912fc 100644 --- a/libs/wingsdk/package.json +++ b/libs/wingsdk/package.json @@ -94,6 +94,7 @@ "@azure/core-paging": "^1.5.0", "@azure/identity": "3.1.3", "@azure/storage-blob": "12.14.0", + "@google-cloud/datastore": "8.4.0", "@google-cloud/storage": "6.9.5", "@smithy/util-stream": "2.0.17", "@smithy/util-utf8": "2.0.0", @@ -109,6 +110,7 @@ "mime": "^3.0.0", "mime-types": "^2.1.35", "nanoid": "^3.3.6", + "protobufjs": "7.2.5", "safe-stable-stringify": "^2.4.3", "stacktracey": "^2.1.8", "ulid": "^2.3.0", @@ -131,6 +133,7 @@ "@azure/core-paging", "@azure/identity", "@azure/storage-blob", + "@google-cloud/datastore", "@google-cloud/storage", "@smithy/util-stream", "@smithy/util-utf8", @@ -145,6 +148,7 @@ "mime", "mime-types", "nanoid", + "protobufjs", "safe-stable-stringify", "stacktracey", "ulid", diff --git a/libs/wingsdk/src/shared-gcp/counter.inflight.ts b/libs/wingsdk/src/shared-gcp/counter.inflight.ts new file mode 100644 index 00000000000..3482d05bad3 --- /dev/null +++ b/libs/wingsdk/src/shared-gcp/counter.inflight.ts @@ -0,0 +1,87 @@ +import { Datastore } from "@google-cloud/datastore"; +import type { ICounterClient } from "../cloud"; + +const DEFAULT_COUNTER_KEY = "counter"; +const COUNTER_ENTITY_KIND = "Counter"; + +export class CounterClient implements ICounterClient { + private readonly client: Datastore; + + constructor( + private readonly databaseName: string, + private readonly initial: number = 0 + ) { + this.client = new Datastore({ databaseId: this.databaseName }); + } + + public async inc( + amount: number = 1, + key: string = DEFAULT_COUNTER_KEY + ): Promise { + const currentValue = await this._getCounterValue(key); + const newValue = currentValue + amount; + + await this._updateCounter(key, newValue); + + // Return the previous value before the increment + return currentValue; + } + + public async dec( + amount: number = 1, + key: string = DEFAULT_COUNTER_KEY + ): Promise { + const currentValue = await this._getCounterValue(key); + const newValue = currentValue - amount; + + await this._updateCounter(key, newValue); + + // Return the previous value before the decrement + return currentValue; + } + + public async set( + value: number, + key: string = DEFAULT_COUNTER_KEY + ): Promise { + await this._updateCounter(key, value); + } + + public async peek(key: string = DEFAULT_COUNTER_KEY): Promise { + return this._getCounterValue(key); + } + + private async _getCounterValue(key: string): Promise { + const counterKey = this.client.key([COUNTER_ENTITY_KIND, key]); + + // Fetch the counter from the datastore + const [existingCounter] = await this.client.get(counterKey); + + // If the counter exists, return its current count + // Else, initialize it with the `initial` value + if (existingCounter) { + return existingCounter.count; + } else { + await this._initCounter(key); + return this.initial; + } + } + + private async _initCounter(key: string): Promise { + const counterEntity = { + key: this.client.key([COUNTER_ENTITY_KIND, key]), + data: { count: this.initial }, + }; + + await this.client.insert(counterEntity); + } + + private async _updateCounter(key: string, newValue: number): Promise { + const counterEntity = { + key: this.client.key([COUNTER_ENTITY_KIND, key]), + data: { count: newValue }, + }; + + await this.client.save(counterEntity); + } +} diff --git a/libs/wingsdk/src/target-tf-gcp/app.ts b/libs/wingsdk/src/target-tf-gcp/app.ts index 91f017e7a59..f51de1aef9b 100644 --- a/libs/wingsdk/src/target-tf-gcp/app.ts +++ b/libs/wingsdk/src/target-tf-gcp/app.ts @@ -1,10 +1,11 @@ import { Bucket } from "./bucket"; +import { Counter } from "./counter"; import { Function } from "./function"; import { Table } from "./table"; import { TestRunner } from "./test-runner"; import { GoogleProvider } from "../.gen/providers/google/provider"; import { RandomProvider } from "../.gen/providers/random/provider"; -import { BUCKET_FQN, FUNCTION_FQN } from "../cloud"; +import { BUCKET_FQN, COUNTER_FQN, FUNCTION_FQN } from "../cloud"; import { AppProps as CdktfAppProps } from "../core"; import { TABLE_FQN } from "../ex"; import { CdktfApp } from "../shared-tf/app"; @@ -92,6 +93,8 @@ export class App extends CdktfApp { return Function; case TABLE_FQN: return Table; + case COUNTER_FQN: + return Counter; } return undefined; diff --git a/libs/wingsdk/src/target-tf-gcp/counter.ts b/libs/wingsdk/src/target-tf-gcp/counter.ts new file mode 100644 index 00000000000..b776458e204 --- /dev/null +++ b/libs/wingsdk/src/target-tf-gcp/counter.ts @@ -0,0 +1,88 @@ +import { Construct } from "constructs"; +import { App } from "./app"; +import { Function as GCPFunction } from "./function"; +import { calculateCounterPermissions } from "./permissions"; +import { FirestoreDatabase } from "../.gen/providers/google/firestore-database"; +import * as cloud from "../cloud"; +import * as core from "../core"; +import { + CaseConventions, + NameOptions, + ResourceNames, +} from "../shared/resource-names"; +import { IInflightHost } from "../std"; + +/** + * Valid database IDs include `(default)` and IDs that conform to the following: + * - Includes only letters, numbers, and hyphen (-) characters. + * - The first character must be a letter. + * - The last character must be a letter or number. + * - Minimum of 4 characters. + * - Maximum of 63 characters. + */ +const NAME_OPTS: NameOptions = { + maxLen: 63, + case: CaseConventions.LOWERCASE, + disallowedRegex: /[^a-zA-Z0-9\-]+/g, + prefix: "wing-counter-", +}; + +/** + * GCP implementation of `cloud.Counter`. + * + * @inflight `@winglang/sdk.cloud.ICounterClient` + */ +export class Counter extends cloud.Counter { + private readonly database: FirestoreDatabase; + + constructor(scope: Construct, id: string, props: cloud.CounterProps = {}) { + super(scope, id, props); + + this.database = new FirestoreDatabase(this, "Default", { + name: ResourceNames.generateName(this, NAME_OPTS), + locationId: (App.of(this) as App).region, + type: "DATASTORE_MODE", + concurrencyMode: "OPTIMISTIC", + appEngineIntegrationMode: "DISABLED", + pointInTimeRecoveryEnablement: "POINT_IN_TIME_RECOVERY_DISABLED", + deleteProtectionState: "DELETE_PROTECTION_DISABLED", + deletionPolicy: "DELETE", + }); + } + + /** @internal */ + public _supportedOps(): string[] { + return [ + cloud.CounterInflightMethods.PEEK, + cloud.CounterInflightMethods.INC, + cloud.CounterInflightMethods.DEC, + cloud.CounterInflightMethods.SET, + ]; + } + + public onLift(host: IInflightHost, ops: string[]): void { + if (!(host instanceof GCPFunction)) { + throw new Error("counters can only be bound by tfgcp.Function for now"); + } + + const permissions = calculateCounterPermissions(ops); + host.addPermissions(permissions); + + host.addEnvironment(this.envName(), this.database.name); + super.onLift(host, ops); + } + + /** @internal */ + public _toInflight(): string { + return core.InflightClient.for( + __dirname.replace("target-tf-gcp", "shared-gcp"), + __filename, + "CounterClient", + [`process.env["${this.envName()}"]`, `${this.initial}`] + ); + } + + private envName(): string { + return `FIRESTORE_DATABASE_NAME_${this.node.addr.slice(-8)}`; + } +} diff --git a/libs/wingsdk/src/target-tf-gcp/function.ts b/libs/wingsdk/src/target-tf-gcp/function.ts index 89239ada945..cc482b4b29c 100644 --- a/libs/wingsdk/src/target-tf-gcp/function.ts +++ b/libs/wingsdk/src/target-tf-gcp/function.ts @@ -180,6 +180,7 @@ export class Function extends cloud.Function { // bundled code is guaranteed to be in a fresh directory const bundle = createBundle(this.entrypoint, [ "@google-cloud/functions-framework", + "@google-cloud/datastore", ]); const packageJson = join(bundle.directory, "package.json"); @@ -191,6 +192,7 @@ export class Function extends cloud.Function { main: "index.js", dependencies: { "@google-cloud/functions-framework": "^3.0.0", + "@google-cloud/datastore": "8.4.0", }, }, null, diff --git a/libs/wingsdk/src/target-tf-gcp/permissions.ts b/libs/wingsdk/src/target-tf-gcp/permissions.ts index e0cc943aa3f..80bea387345 100644 --- a/libs/wingsdk/src/target-tf-gcp/permissions.ts +++ b/libs/wingsdk/src/target-tf-gcp/permissions.ts @@ -48,3 +48,34 @@ export function calculateBucketPermissions(ops: string[]): string[] { return permissions; } + +export function calculateCounterPermissions(ops: string[]): string[] { + const permissions: string[] = []; + + if ( + ops.includes(cloud.CounterInflightMethods.PEEK) || + ops.includes(cloud.CounterInflightMethods.INC) || + ops.includes(cloud.CounterInflightMethods.DEC) + ) { + permissions.push("datastore.entities.get"); + } + + if ( + ops.includes(cloud.CounterInflightMethods.PEEK) || + ops.includes(cloud.CounterInflightMethods.INC) || + ops.includes(cloud.CounterInflightMethods.DEC) || + ops.includes(cloud.CounterInflightMethods.SET) + ) { + permissions.push("datastore.entities.create"); + } + + if ( + ops.includes(cloud.CounterInflightMethods.INC) || + ops.includes(cloud.CounterInflightMethods.DEC) || + ops.includes(cloud.CounterInflightMethods.SET) + ) { + permissions.push("datastore.entities.update"); + } + + return permissions; +} diff --git a/package.json b/package.json index cbcea0d5b69..0c201d57b20 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "wasi-js@1.7.3": "patches/wasi-js@1.7.3.patch", "jsii@5.0.11": "patches/jsii@5.0.11.patch", "esbuild-wasm@0.18.20": "patches/esbuild-wasm@0.18.20.patch", - "mime@3.0.0": "patches/mime@3.0.0.patch" + "mime@3.0.0": "patches/mime@3.0.0.patch", + "protobufjs@7.2.5": "patches/protobufjs@7.2.5.patch" } } } diff --git a/patches/protobufjs@7.2.5.patch b/patches/protobufjs@7.2.5.patch new file mode 100644 index 00000000000..536336998c9 --- /dev/null +++ b/patches/protobufjs@7.2.5.patch @@ -0,0 +1,12 @@ +diff --git a/package.json b/package.json +index 37c744ff87811320ade6218fe7e45646b95f2015..69248daedf8196e02596725a4c00c5b7999aa6f4 100644 +--- a/package.json ++++ b/package.json +@@ -40,7 +40,6 @@ + "lint:types": "tslint \"**/*.d.ts\" -e \"**/node_modules/**\" -t stylish -c config/tslint.json", + "pages": "node scripts/pages", + "prepublish": "cd cli && npm install && cd .. && npm run build", +- "postinstall": "node scripts/postinstall", + "prof": "node bench/prof", + "test": "npm run test:sources && npm run test:types", + "test:sources": "tape -r ./lib/tape-adapter tests/*.js tests/node/*.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 51d1edce4e4..33d8d459cba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ patchedDependencies: mime@3.0.0: hash: 2he2uszztbibyal6zfzmv2a2oa path: patches/mime@3.0.0.patch + protobufjs@7.2.5: + hash: plkkb5oxv62w7nyvt6cqmvgk4q + path: patches/protobufjs@7.2.5.patch wasi-js@1.7.3: hash: rmwvp46j2ligfusbdx5dzh4a3q path: patches/wasi-js@1.7.3.patch @@ -1289,6 +1292,9 @@ importers: '@azure/storage-blob': specifier: 12.14.0 version: 12.14.0 + '@google-cloud/datastore': + specifier: 8.4.0 + version: 8.4.0 '@google-cloud/storage': specifier: 6.9.5 version: 6.9.5 @@ -1334,6 +1340,9 @@ importers: nanoid: specifier: ^3.3.6 version: 3.3.6 + protobufjs: + specifier: 7.2.5 + version: 7.2.5(patch_hash=plkkb5oxv62w7nyvt6cqmvgk4q) safe-stable-stringify: specifier: ^2.4.3 version: 2.4.3 @@ -5631,6 +5640,23 @@ packages: resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} dev: true + /@google-cloud/datastore@8.4.0: + resolution: {integrity: sha512-zSU4R4LkVBTPdZJi8pK0QPe+3ZQL5+1mFXI7Yh5mdDcJhtX2Y5VD9wXsEJ0N48kpiA5V6+cxh4g0NB+mAyQbKg==} + engines: {node: '>=14.0.0'} + dependencies: + '@google-cloud/promisify': 4.0.0 + arrify: 2.0.1 + concat-stream: 2.0.0 + extend: 3.0.2 + google-gax: 4.0.5 + is: 3.3.0 + split-array-stream: 2.0.0 + stream-events: 1.0.5 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@google-cloud/paginator@3.0.7: resolution: {integrity: sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==} engines: {node: '>=10'} @@ -5649,6 +5675,11 @@ packages: engines: {node: '>=12'} dev: false + /@google-cloud/promisify@4.0.0: + resolution: {integrity: sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==} + engines: {node: '>=14'} + dev: false + /@google-cloud/storage@6.9.5: resolution: {integrity: sha512-fcLsDA8YKcGuqvhk0XTjJGVpG9dzs5Em8IcUjSjspYvERuHYqMy9CMChWapSjv3Lyw//exa3mv4nUxPlV93BnA==} engines: {node: '>=12'} @@ -5675,6 +5706,25 @@ packages: - supports-color dev: false + /@grpc/grpc-js@1.9.9: + resolution: {integrity: sha512-vQ1qwi/Kiyprt+uhb1+rHMpyk4CVRMTGNUGGPRGS7pLNfWkdCHrGEnT6T3/JyC2VZgoOX/X1KwdoU0WYQAeYcQ==} + engines: {node: ^8.13.0 || >=10.10.0} + dependencies: + '@grpc/proto-loader': 0.7.10 + '@types/node': 18.18.4 + dev: false + + /@grpc/proto-loader@0.7.10: + resolution: {integrity: sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + lodash.camelcase: 4.3.0 + long: 5.2.3 + protobufjs: 7.2.5(patch_hash=plkkb5oxv62w7nyvt6cqmvgk4q) + yargs: 17.7.2 + dev: false + /@gwhitney/detect-indent@7.0.1: resolution: {integrity: sha512-7bQW+gkKa2kKZPeJf6+c6gFK9ARxQfn+FKy9ScTBppyKRWH2KzsmweXUoklqeEiHiNVWaeP5csIdsNq6w7QhzA==} engines: {node: '>=12.20'} @@ -7613,6 +7663,49 @@ packages: resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} dev: false + /@protobufjs/aspromise@1.1.2: + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + dev: false + + /@protobufjs/base64@1.1.2: + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + dev: false + + /@protobufjs/codegen@2.0.4: + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + dev: false + + /@protobufjs/eventemitter@1.1.0: + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + dev: false + + /@protobufjs/fetch@1.1.0: + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + dev: false + + /@protobufjs/float@1.0.2: + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + dev: false + + /@protobufjs/inquire@1.1.0: + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + dev: false + + /@protobufjs/path@1.1.2: + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + dev: false + + /@protobufjs/pool@1.1.0: + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + dev: false + + /@protobufjs/utf8@1.1.0: + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + dev: false + /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: @@ -10477,6 +10570,10 @@ packages: '@types/node': 18.18.4 dev: true + /@types/caseless@0.12.4: + resolution: {integrity: sha512-2in/lrHRNmDvHPgyormtEralhPcN3An1gLjJzj2Bw145VBxkQ75JEXW6CTdMAwShiHQcYsl2d10IjQSdJSJz4g==} + dev: false + /@types/chai-subset@1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: @@ -10748,6 +10845,10 @@ packages: resolution: {integrity: sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==} dev: true + /@types/long@4.0.2: + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + dev: false + /@types/mdast@4.0.3: resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==} dependencies: @@ -10906,6 +11007,15 @@ packages: '@types/scheduler': 0.16.4 csstype: 3.1.2 + /@types/request@2.48.11: + resolution: {integrity: sha512-HuihY1+Vss5RS9ZHzRyTGIzwPTdrJBkCm/mAeLRYrOQu/MGqyezKXWOK1VhCnR+SDbp9G2mRUP+OVEqCrzpcfA==} + dependencies: + '@types/caseless': 0.12.4 + '@types/node': 18.18.4 + '@types/tough-cookie': 4.0.4 + form-data: 2.5.1 + dev: false + /@types/scheduler@0.16.4: resolution: {integrity: sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==} @@ -10957,6 +11067,10 @@ packages: minipass: 4.2.8 dev: true + /@types/tough-cookie@4.0.4: + resolution: {integrity: sha512-95Sfz4nvMAb0Nl9DTxN3j64adfwfbBPEYq14VN7zT5J5O2M9V6iZMIIQU1U+pJyl9agHYHNCqhCXgyEtIRRa5A==} + dev: false + /@types/triple-beam@1.3.3: resolution: {integrity: sha512-6tOUG+nVHn0cJbVp25JFayS5UE6+xlbcNF9Lo9mU7U0zk3zeUShZied4YEQZjy1JBF043FSkdXw8YkUJuVtB5g==} requiresBuild: true @@ -13682,7 +13796,6 @@ packages: inherits: 2.0.4 readable-stream: 3.6.2 typedarray: 0.0.6 - dev: true /concordance@5.0.4: resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} @@ -14548,7 +14661,7 @@ packages: dependencies: semver: 7.5.4 shelljs: 0.8.5 - typescript: 5.4.0-dev.20240118 + typescript: 5.4.0-dev.20240115 dev: true /dset@3.1.2: @@ -16016,6 +16129,15 @@ packages: engines: {node: '>= 14.17'} dev: true + /form-data@2.5.1: + resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} + engines: {node: '>= 0.12'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /form-data@3.0.1: resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} @@ -16201,6 +16323,19 @@ packages: - supports-color dev: false + /gaxios@6.1.1: + resolution: {integrity: sha512-bw8smrX+XlAoo9o1JAksBwX+hi/RG15J+NTSxmNPIclKC3ZVK6C2afwY8OSdRvOK0+ZLecUJYtj2MmjOt3Dm0w==} + engines: {node: '>=14'} + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.2 + is-stream: 2.0.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /gcp-metadata@5.3.0: resolution: {integrity: sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==} engines: {node: '>=12'} @@ -16212,6 +16347,17 @@ packages: - supports-color dev: false + /gcp-metadata@6.0.0: + resolution: {integrity: sha512-Ozxyi23/1Ar51wjUT2RDklK+3HxqDr8TLBNK8rBBFQ7T85iIGnXnVusauj06QyqCXRFZig8LZC+TUddWbndlpQ==} + engines: {node: '>=14'} + dependencies: + gaxios: 6.1.1 + json-bigint: 1.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /generic-pool@3.9.0: resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} engines: {node: '>= 4'} @@ -16500,6 +16646,41 @@ packages: - supports-color dev: false + /google-auth-library@9.2.0: + resolution: {integrity: sha512-1oV3p0JhNEhVbj26eF3FAJcv9MXXQt4S0wcvKZaDbl4oHq5V3UJoSbsGZGQNcjoCdhW4kDSwOs11wLlHog3fgQ==} + engines: {node: '>=14'} + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 6.1.1 + gcp-metadata: 6.0.0 + gtoken: 7.0.1 + jws: 4.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + + /google-gax@4.0.5: + resolution: {integrity: sha512-yLoYtp4zE+8OQA74oBEbNkbzI6c95W01JSL7RqC8XERKpRvj3ytZp1dgnbA6G9aRsc8pZB25xWYBcCmrbYOEhA==} + engines: {node: '>=14'} + dependencies: + '@grpc/grpc-js': 1.9.9 + '@grpc/proto-loader': 0.7.10 + '@types/long': 4.0.2 + abort-controller: 3.0.0 + duplexify: 4.1.2 + google-auth-library: 9.2.0 + node-fetch: 2.7.0 + object-hash: 3.0.0 + proto3-json-serializer: 2.0.0 + protobufjs: 7.2.5(patch_hash=plkkb5oxv62w7nyvt6cqmvgk4q) + retry-request: 7.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /google-p12-pem@4.0.1: resolution: {integrity: sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==} engines: {node: '>=12.0.0'} @@ -16584,6 +16765,17 @@ packages: - supports-color dev: false + /gtoken@7.0.1: + resolution: {integrity: sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==} + engines: {node: '>=14.0.0'} + dependencies: + gaxios: 6.1.1 + jws: 4.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /gunzip-maybe@1.4.2: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} hasBin: true @@ -17371,6 +17563,10 @@ packages: dependencies: call-bind: 1.0.2 + /is-stream-ended@0.1.4: + resolution: {integrity: sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==} + dev: false + /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -17455,6 +17651,10 @@ packages: engines: {node: '>=12'} dev: true + /is@3.3.0: + resolution: {integrity: sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==} + dev: false + /isarray@0.0.1: resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} dev: true @@ -19209,6 +19409,10 @@ packages: dependencies: p-locate: 5.0.0 + /lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + dev: false + /lodash.clonedeep@4.5.0: resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} dev: false @@ -19327,6 +19531,10 @@ packages: dev: false optional: true + /long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + dev: false + /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -21465,6 +21673,33 @@ packages: /proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + /proto3-json-serializer@2.0.0: + resolution: {integrity: sha512-FB/YaNrpiPkyQNSNPilpn8qn0KdEfkgmJ9JP93PQyF/U4bAiXY5BiUdDhiDO4S48uSQ6AesklgVlrKiqZPzegw==} + engines: {node: '>=14.0.0'} + dependencies: + protobufjs: 7.2.5(patch_hash=plkkb5oxv62w7nyvt6cqmvgk4q) + dev: false + + /protobufjs@7.2.5(patch_hash=plkkb5oxv62w7nyvt6cqmvgk4q): + resolution: {integrity: sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==} + engines: {node: '>=12.0.0'} + requiresBuild: true + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 18.18.4 + long: 5.2.3 + dev: false + patched: true + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -22316,6 +22551,19 @@ packages: - supports-color dev: false + /retry-request@7.0.1: + resolution: {integrity: sha512-ZI6vJp9rfB71mrZpw+n9p/B6HCsd7QJlSEQftZ+xfJzr3cQ9EPGKw1FF0BnViJ0fYREX6FhymBD2CARpmsFciQ==} + engines: {node: '>=14'} + dependencies: + '@types/request': 2.48.11 + debug: 4.3.4 + extend: 3.0.2 + teeny-request: 9.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -22897,6 +23145,12 @@ packages: engines: {node: '>=8'} dev: true + /split-array-stream@2.0.0: + resolution: {integrity: sha512-hmMswlVY91WvGMxs0k8MRgq8zb2mSen4FmDNc5AFiTWtrBpdZN6nwD6kROVe4vNL+ywrvbCKsWVCnEd4riELIg==} + dependencies: + is-stream-ended: 0.1.4 + dev: false + /split2@3.2.2: resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} dependencies: @@ -23365,6 +23619,20 @@ packages: - supports-color dev: false + /teeny-request@9.0.0: + resolution: {integrity: sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==} + engines: {node: '>=14'} + dependencies: + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + node-fetch: 2.7.0 + stream-events: 1.0.5 + uuid: 9.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /telejson@7.2.0: resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==} dependencies: @@ -24208,7 +24476,6 @@ packages: /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - dev: true /typescript@3.9.10: resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} @@ -24243,8 +24510,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - /typescript@5.4.0-dev.20240118: - resolution: {integrity: sha512-TkIGY1JFa2/uWOcKuIuHroLZrOO6JDWSDCzVNDhgcKx8aSquBr7Ih9//PSsLZ0YkxkNOvvLySGxACPhUjweTEg==} + /typescript@5.4.0-dev.20240115: + resolution: {integrity: sha512-p3nYa7pku8FHvfLDyiDcplZbKXEQTcZqtvXN6JTBu/u5cNLinBzOiKA3cVfHcgudzCUMtU5ke94dpwFNr+U3qw==} engines: {node: '>=14.17'} hasBin: true dev: true diff --git a/tools/hangar/__snapshots__/compatibility-spy.ts.snap b/tools/hangar/__snapshots__/compatibility-spy.ts.snap index 7dfbd7cfbb2..205ab5db840 100644 --- a/tools/hangar/__snapshots__/compatibility-spy.ts.snap +++ b/tools/hangar/__snapshots__/compatibility-spy.ts.snap @@ -64,7 +64,6 @@ exports[`set.test.w 1`] = ` \\"findTests\\" ], \\"Counter\\": [ - \\"inc\\", \\"peek\\", \\"set\\" ] diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_compile_tf-aws.md index e5eaf258c75..47f0bb8a07b 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_compile_tf-aws.md @@ -18,11 +18,11 @@ }, "resource": { "aws_dynamodb_table": { - "cloudCounter": { + "counter1": { "//": { "metadata": { - "path": "root/Default/Default/cloud.Counter/Default", - "uniqueId": "cloudCounter" + "path": "root/Default/Default/counter1/Default", + "uniqueId": "counter1" } }, "attribute": [ @@ -33,7 +33,24 @@ ], "billing_mode": "PAY_PER_REQUEST", "hash_key": "id", - "name": "wing-counter-cloud.Counter-c866f225" + "name": "wing-counter-counter1-c8e8f5f5" + }, + "counter2": { + "//": { + "metadata": { + "path": "root/Default/Default/counter2/Default", + "uniqueId": "counter2" + } + }, + "attribute": [ + { + "name": "id", + "type": "S" + } + ], + "billing_mode": "PAY_PER_REQUEST", + "hash_key": "id", + "name": "wing-counter-counter2-c863f110" } } } diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_test_sim.md index b4c8b0e21ea..49feb0b1a4e 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_test_sim.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/dec.test.w_test_sim.md @@ -2,8 +2,8 @@ ## stdout.log ```log -pass ─ dec.test.wsim » root/env0/test:dec -pass ─ dec.test.wsim » root/env1/test:key dec +pass ─ dec.test.wsim » root/env0/test:dec() +pass ─ dec.test.wsim » root/env1/test:dec() with custom key Tests 2 passed (2) diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_compile_tf-aws.md index 485695e7caf..254e11561e7 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_compile_tf-aws.md @@ -18,11 +18,11 @@ }, "resource": { "aws_dynamodb_table": { - "cloudCounter": { + "counter1": { "//": { "metadata": { - "path": "root/Default/Default/cloud.Counter/Default", - "uniqueId": "cloudCounter" + "path": "root/Default/Default/counter1/Default", + "uniqueId": "counter1" } }, "attribute": [ @@ -33,7 +33,24 @@ ], "billing_mode": "PAY_PER_REQUEST", "hash_key": "id", - "name": "wing-counter-cloud.Counter-c866f225" + "name": "wing-counter-counter1-c8e8f5f5" + }, + "counter2": { + "//": { + "metadata": { + "path": "root/Default/Default/counter2/Default", + "uniqueId": "counter2" + } + }, + "attribute": [ + { + "name": "id", + "type": "S" + } + ], + "billing_mode": "PAY_PER_REQUEST", + "hash_key": "id", + "name": "wing-counter-counter2-c863f110" } } } diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_test_sim.md index fd0c31a94c8..d3fff54fcd8 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_test_sim.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/inc.test.w_test_sim.md @@ -2,8 +2,8 @@ ## stdout.log ```log -pass ─ inc.test.wsim » root/env0/test:inc -pass ─ inc.test.wsim » root/env1/test:key inc +pass ─ inc.test.wsim » root/env0/test:inc() +pass ─ inc.test.wsim » root/env1/test:inc() with custom key Tests 2 passed (2) diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_compile_tf-aws.md index 0e16be63523..30aa7648a60 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_compile_tf-aws.md @@ -18,11 +18,11 @@ }, "resource": { "aws_dynamodb_table": { - "cloudCounter": { + "counter1": { "//": { "metadata": { - "path": "root/Default/Default/cloud.Counter/Default", - "uniqueId": "cloudCounter" + "path": "root/Default/Default/counter1/Default", + "uniqueId": "counter1" } }, "attribute": [ @@ -33,7 +33,24 @@ ], "billing_mode": "PAY_PER_REQUEST", "hash_key": "id", - "name": "wing-counter-cloud.Counter-c866f225" + "name": "wing-counter-counter1-c8e8f5f5" + }, + "counter2": { + "//": { + "metadata": { + "path": "root/Default/Default/counter2/Default", + "uniqueId": "counter2" + } + }, + "attribute": [ + { + "name": "id", + "type": "S" + } + ], + "billing_mode": "PAY_PER_REQUEST", + "hash_key": "id", + "name": "wing-counter-counter2-c863f110" } } } diff --git a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_test_sim.md index 38a02047d64..0d436c0e68a 100644 --- a/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_test_sim.md +++ b/tools/hangar/__snapshots__/test_corpus/sdk_tests/counter/set.test.w_test_sim.md @@ -2,8 +2,8 @@ ## stdout.log ```log -pass ─ set.test.wsim » root/env0/test:set -pass ─ set.test.wsim » root/env1/test:key set +pass ─ set.test.wsim » root/env0/test:set() +pass ─ set.test.wsim » root/env1/test:set() with custom key Tests 2 passed (2)